package com.knecon.fforesight.service.layoutparser.processor.model.text;

import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;

import org.apache.pdfbox.text.TextPosition;

import com.knecon.fforesight.service.layoutparser.processor.docstrum.model.TextBoundingBox;
import com.knecon.fforesight.service.layoutparser.processor.docstrum.utils.FastAtan2;

import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.SneakyThrows;
import lombok.experimental.FieldDefaults;
import lombok.experimental.SuperBuilder;

@Data
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = true)
@FieldDefaults(level = AccessLevel.PRIVATE)
public class RedTextPosition extends TextBoundingBox {

    public final static int HEIGHT_PADDING = 2;

    String unicode;

    // estimated using the TextMatrix in radians
    float exactDir;

    float widthOfSpace;

    float fontSizeInPt;

    String fontName;


    @SneakyThrows
    public static RedTextPosition fromTextPosition(TextPosition textPosition) {

        var pos = new RedTextPosition();
        pos.setUnicode(textPosition.getUnicode());
        pos.setWidthOfSpace(textPosition.getWidthOfSpace());
        pos.setFontSizeInPt(textPosition.getFontSizeInPt());
        pos.setFontName(textPosition.getFont().getName());
        pos.setExactDir((float) FastAtan2.fastAtan2(textPosition.getTextMatrix().getShearY(), textPosition.getTextMatrix().getScaleX()));
        pos.setDir(TextDirection.fromDegrees(textPosition.getDir()));

        //TODO: There is a mismatch in the java coords of the text and the rulings,
        // I guess if we start with the initial user space positions and transform them the same way we do the rulings it would work.
        pos.setBBox(new Rectangle2D.Float(textPosition.getX(), textPosition.getY(), textPosition.getWidthDirAdj(), textPosition.getHeight()));

        float textHeight = textPosition.getHeight() + 2 * HEIGHT_PADDING;
        Rectangle2D.Float dirAdjPosition = new Rectangle2D.Float(textPosition.getXDirAdj(),
                                                                 textPosition.getYDirAdj() - textHeight,
                                                                 textPosition.getWidthDirAdj(),
                                                                 textHeight + HEIGHT_PADDING);

        pos.setBBoxDirAdj(dirAdjPosition);

        AffineTransform affineTransform = getRotationMatrix(TextDirection.fromDegrees(textPosition.getDir()), textPosition.getPageWidth(), textPosition.getPageHeight());
        Rectangle2D bBoxInitialUserSpace = affineTransform.createTransformedShape(dirAdjPosition).getBounds2D();

        pos.setBBoxPdf(bBoxInitialUserSpace); // These are definitely correct

        return pos;
    }


    private static AffineTransform getRotationMatrix(TextDirection textDirection, float pageWidth, float pageHeight) {

        AffineTransform transform = new AffineTransform();

        if (textDirection == TextDirection.ZERO || textDirection == TextDirection.HALF_CIRCLE) {
            transform.rotate(textDirection.getRadians(), pageWidth / 2f, pageHeight / 2f);
            transform.translate(0f, pageHeight);
        } else if (textDirection == TextDirection.QUARTER_CIRCLE) {
            transform.rotate(textDirection.getRadians(), pageWidth / 2f, pageWidth / 2f);
            transform.translate(0f, pageWidth);
        } else {
            transform.rotate(textDirection.getRadians(), pageHeight / 2f, pageHeight / 2f);
            transform.translate(0f, pageWidth);
        }
        transform.scale(1., -1.);
        return transform;
    }

}
