package com.knecon.fforesight.service.layoutparser.processor.services.graphics;

import java.awt.geom.Rectangle2D;
import java.util.List;
import java.util.stream.Collectors;

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.springframework.stereotype.Service;

import com.knecon.fforesight.service.layoutparser.processor.model.table.CleanRulings;
import com.knecon.fforesight.service.layoutparser.processor.model.table.Ruling;
import com.knecon.fforesight.service.layoutparser.processor.model.text.TextPositionSequence;
import com.knecon.fforesight.service.layoutparser.processor.services.factory.SearchTextWithTextPositionFactory;
import com.knecon.fforesight.service.layoutparser.processor.utils.RectangleTransformations;

import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;

@Service
@RequiredArgsConstructor
public class GraphicExtractorService {

    private final GraphicsClusteringService graphicsClusteringService;
    private final FindGraphicsRaster findGraphicsRaster;


    @SneakyThrows
    public List<Box> extractPathElementGraphics(PDDocument pdDocument,
                                                PDPage pdPage,
                                                int pageNumber,
                                                CleanRulings cleanRulings,
                                                List<TextPositionSequence> textPositionSequences,
                                                boolean graphicsRaster) {

        List<Box> characterBBoxes = getCharacterBBoxes(textPositionSequences);
        List<Box> classifiedRulingsBoxes = getLineBBoxesOfAllClassifiedRulings(cleanRulings);

        GraphicBBDetector graphicBBDetector = new GraphicBBDetector(pdPage, true);
        List<Box> graphicBBoxes = graphicBBDetector.findGraphicBB();

        if (graphicsRaster) {
            // This should only be used if ocr was performed, it is currently in an early stage and needs to be improved.
            graphicBBoxes.addAll(findGraphicsRaster.findCCBoundingBoxes(pdDocument,
                                                                        characterBBoxes.stream()
                                                                                .map(box -> new Rectangle2D.Double(box.x1 - 2, box.y1 - 2, box.width() + 4, box.height() + 4))
                                                                                .collect(Collectors.toList()),
                                                                        PageInformation.fromPDPage(pageNumber, pdPage)));
        }

        List<Box> filteredGraphicBBoxes = graphicBBoxes.stream()
                .filter(box -> !box.intersectsAny(classifiedRulingsBoxes, 4))
                .collect(Collectors.toList());

        List<Box> clusters = graphicsClusteringService.getClusters(filteredGraphicBBoxes, 14);

        return clusters.stream()
                .filter(box -> box.area() > 500 && box.height() > 50 && box.width() > 50)
                .toList();
    }


    private List<Box> getCharacterBBoxes(List<TextPositionSequence> textPositionSequences) {

        return textPositionSequences.stream()
                .map(pos -> pos.getTextPositions()
                        .stream()
                        .map(tp -> SearchTextWithTextPositionFactory.mapRedTextPositionToInitialUserSpace(tp, pos))
                        .collect(RectangleTransformations.collectBBox()))
                .map(Box::new)
                .collect(Collectors.toList());
    }


    private List<Box> getLineBBoxesOfAllClassifiedRulings(CleanRulings cleanRulings) {

        return cleanRulings.buildAll()
                .stream()
                .filter(ruling -> !ruling.getClassification().equals(Ruling.Classification.OTHER))
                .map(h -> new Box(h.x1, h.y1, h.x2, h.y2))
                .collect(Collectors.toList());
    }

}
