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

import java.util.List;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.springframework.stereotype.Service;

import com.knecon.fforesight.service.layoutparser.processor.model.AbstractPageBlock;
import com.knecon.fforesight.service.layoutparser.processor.model.ClassificationDocument;
import com.knecon.fforesight.service.layoutparser.processor.model.ClassificationPage;
import com.knecon.fforesight.service.layoutparser.processor.model.PageBlockType;
import com.knecon.fforesight.service.layoutparser.processor.model.text.TextPageBlock;
import com.knecon.fforesight.service.layoutparser.processor.utils.HeaderFooterDetection;
import com.knecon.fforesight.service.layoutparser.processor.utils.MarkedContentUtils;
import com.knecon.fforesight.service.layoutparser.processor.utils.PositionUtils;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
@RequiredArgsConstructor
public class DocuMineClassificationService {

    private static final Pattern HEADLINE_WITH_IDENTIFER_PATTERN = Pattern.compile("^([1-9]\\d?\\.){1,3}\\d{1,2}\\.?\\s[0-9A-Za-z \\[\\]]{2,50}", Pattern.CASE_INSENSITIVE);
    private static final Pattern AT_LEAST_3_PATTERN = Pattern.compile("\\p{L}{3,}", Pattern.CASE_INSENSITIVE);
    private static final Pattern HEADLINE_PATTTERN_WITH_SLASHES = Pattern.compile("^(\\d{1,1}\\.){1,3}\\d{1,2}\\.?\\s[a-z]{1,2}\\/[a-z]{1,2}.*");


    public void classifyDocument(ClassificationDocument document) {

        List<Float> headlineFontSizes = document.getFontSizeCounter().getHighterThanMostPopular();

        log.debug("Document FontSize counters are: {}", document.getFontSizeCounter().getCountPerValue());

        HeadlineClassificationService headlineClassificationService = new HeadlineClassificationService();

        for (ClassificationPage page : document.getPages()) {
            classifyPage(headlineClassificationService, page, document, headlineFontSizes);
        }
    }


    private void classifyPage(HeadlineClassificationService headlineClassificationService,
                              ClassificationPage page,
                              ClassificationDocument document,
                              List<Float> headlineFontSizes) {

        for (AbstractPageBlock textBlock : page.getTextBlocks()) {
            if (textBlock instanceof TextPageBlock) {
                classifyBlock(headlineClassificationService, (TextPageBlock) textBlock, page, document, headlineFontSizes);
            }
        }
    }


    private void classifyBlock(HeadlineClassificationService headlineClassificationService,
                               TextPageBlock textBlock,
                               ClassificationPage page,
                               ClassificationDocument document,
                               List<Float> headlineFontSizes) {

        log.debug("headlineFontSizes: {}", headlineFontSizes);
        var bodyTextFrame = page.getBodyTextFrame();

        Matcher headlineWithIdentifierMatcher = HEADLINE_WITH_IDENTIFER_PATTERN.matcher(textBlock.toString());
        Matcher atLeast3Matcher = AT_LEAST_3_PATTERN.matcher(textBlock.toString());
        Matcher headlineWithSlashesMatcher = HEADLINE_PATTTERN_WITH_SLASHES.matcher(textBlock.toString());

        if (textBlock.getClassification() != null && textBlock.getClassification().isHeadline()) {
            headlineClassificationService.setLastHeadlineFromOutline(textBlock);
            return;
        }
        if (document.getFontSizeCounter().getMostPopular() == null) {
            textBlock.setClassification(PageBlockType.OTHER);
            return;
        }
        if (MarkedContentUtils.intersects(textBlock, page.getMarkedContentBboxPerType(), MarkedContentUtils.HEADER) //
            || (PositionUtils.isOverBodyTextFrame(bodyTextFrame, textBlock, page.getRotation()) //
                && (document.getFontSizeCounter().getMostPopular() == null //
                    || textBlock.getHighestFontSize() <= document.getFontSizeCounter().getMostPopular()))) {
            textBlock.setClassification(PageBlockType.HEADER);

        } else if (MarkedContentUtils.intersects(textBlock, page.getMarkedContentBboxPerType(), MarkedContentUtils.FOOTER)
                   || (PositionUtils.isUnderBodyTextFrame(bodyTextFrame,
                                                          textBlock,
                                                          page.getRotation())
                       && (document.getFontSizeCounter().getMostPopular()
                           == null
                           || textBlock.getHighestFontSize()
                              <= document.getFontSizeCounter()
                                      .getMostPopular()))
                   || HeaderFooterDetection.isLikelyFooter(textBlock, document, page)) {
            textBlock.setClassification(PageBlockType.FOOTER);
        } else if (page.getPageNumber() == 1 && (PositionUtils.getHeightDifferenceBetweenChunkWordAndDocumentWord(textBlock, document.getTextHeightCounter().getMostPopular()) > 2.5
                                                 && textBlock.getHighestFontSize() > document.getFontSizeCounter().getMostPopular() || page.getTextBlocks().size() == 1)) {
            if (!Pattern.matches("[0-9]+", textBlock.toString())) {
                textBlock.setClassification(PageBlockType.TITLE);
            }
        } else if (textBlock.getText().length() > 5
                   && (textBlock.getMostPopularWordHeight() > document.getTextHeightCounter().getMostPopular()
                       || textBlock.getMostPopularWordFontSize() > document.getFontSizeCounter().getMostPopular())
                   && PositionUtils.getApproxLineCount(textBlock) < 5.9

                   && (textBlock.getMostPopularWordStyle().contains("bold")
                       && Character.isDigit(textBlock.toString().charAt(0))
                       && atLeast3Matcher.reset().find()
                       && !textBlock.toString().contains(":") //
                       || textBlock.toString().equals(textBlock.toString().toUpperCase(Locale.ROOT)) && atLeast3Matcher.reset().find() && !textBlock.toString().contains(":") //
                       || textBlock.toString().startsWith("APPENDIX") //
                       || textBlock.toString().startsWith("FIGURE") //
                       || textBlock.toString().startsWith("Continued TABLE") //
                       || textBlock.toString().startsWith("TABLE"))
                   && !textBlock.toString().endsWith(":")
                   && atLeast3Matcher.reset().find()) {
            PageBlockType headlineType = PageBlockType.getHeadlineType(1);
            headlineClassificationService.classifyHeadline(textBlock, headlineType);
            document.setHeadlines(true);

        } else if (headlineWithIdentifierMatcher.reset().find()
                   && PositionUtils.getApproxLineCount(textBlock) < 2.9
                   && atLeast3Matcher.reset().find()
                   && !headlineWithSlashesMatcher.reset().matches()) {
            PageBlockType headlineType = PageBlockType.getHeadlineType(2);
            headlineClassificationService.classifyHeadline(textBlock, headlineType);
            document.setHeadlines(true);
        } else if (PositionUtils.isWithinBodyTextFrame(bodyTextFrame, textBlock)
                   && textBlock.getMostPopularWordFontSize() == document.getFontSizeCounter().getMostPopular()
                   && textBlock.getMostPopularWordStyle().equals("bold")
                   && !document.getFontStyleCounter().getMostPopular().equals("bold")) {
            textBlock.setClassification(PageBlockType.PARAGRAPH_BOLD);
        } else if (PositionUtils.isWithinBodyTextFrame(bodyTextFrame, textBlock)
                   && textBlock.getMostPopularWordFont().equals(document.getFontCounter().getMostPopular())
                   && textBlock.getMostPopularWordStyle().equals(document.getFontStyleCounter().getMostPopular())
                   && textBlock.getMostPopularWordFontSize() == document.getFontSizeCounter().getMostPopular()) {
            textBlock.setClassification(PageBlockType.PARAGRAPH);
        } else if (PositionUtils.isWithinBodyTextFrame(bodyTextFrame, textBlock)
                   && textBlock.getMostPopularWordFontSize() == document.getFontSizeCounter().getMostPopular()
                   && textBlock.getMostPopularWordStyle().equals("italic")
                   && !document.getFontStyleCounter().getMostPopular().equals("italic")
                   && PositionUtils.getApproxLineCount(textBlock) < 2.9) {
            textBlock.setClassification(PageBlockType.PARAGRAPH_ITALIC);
        } else if (PositionUtils.isWithinBodyTextFrame(bodyTextFrame, textBlock)) {
            textBlock.setClassification(PageBlockType.PARAGRAPH_UNKNOWN);
        } else {
            textBlock.setClassification(PageBlockType.OTHER);
        }
    }

}