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

import java.io.File;
import java.util.List;

import org.springframework.stereotype.Service;

import com.iqser.red.service.redaction.v1.server.model.document.nodes.Document;
import com.iqser.red.service.redaction.v1.server.model.document.nodes.Headline;
import com.iqser.red.service.redaction.v1.server.model.document.nodes.Image;
import com.iqser.red.service.redaction.v1.server.model.document.nodes.Paragraph;
import com.iqser.red.service.redaction.v1.server.model.document.nodes.Table;
import com.knecon.fforesight.service.layoutparser.internal.api.queue.LayoutParsingType;
import com.knecon.fforesight.service.layoutparser.processor.model.DocumentWithVisualization;
import com.knecon.fforesight.service.layoutparser.processor.services.mapper.OutlineMapper;
import com.knecon.fforesight.service.layoutparser.processor.visualization.LayoutGrid;
import com.knecon.fforesight.service.viewerdoc.model.Outline;
import com.knecon.fforesight.service.viewerdoc.service.PDFTronViewerDocumentService;

import io.micrometer.observation.annotation.Observed;
import lombok.AccessLevel;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.experimental.FieldDefaults;

@Service
@RequiredArgsConstructor
@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true)
public class LayoutGridService {

    PDFTronViewerDocumentService viewerDocumentService;


    @SneakyThrows
    @Observed(name = "ViewerDocumentService", contextualName = "create-viewer-document")
    public void addLayoutGrid(File originFile,
                              DocumentWithVisualization document,
                              File destinationFile,
                              LayoutParsingType layoutParsingType,
                              String layoutParserVersion,
                              boolean layerVisibilityDefaultValue) {

        String layoutParsingTypeName = layoutParsingType.name();
        LayoutGrid layoutGrid = createLayoutGrid(document.document(), layoutParserVersion, layoutParsingTypeName);
        Outline outline = OutlineMapper.createOutline(document.document());
        layoutGrid.setVisibleByDefault(layerVisibilityDefaultValue);

        document.layoutDebugLayer().addSentenceVisualization(document.document().getTextBlock());
        document.layoutDebugLayer().addOutlineHeadlines(document.document());

        if (document.layoutDebugLayer().isActive()) {
            viewerDocumentService.addLayerGroups(originFile,
                                                 destinationFile,
                                                 List.of(layoutGrid, document.layoutDebugLayer()),
                                                 layoutParserVersion,
                                                 layoutParsingTypeName,
                                                 outline);
        } else {
            viewerDocumentService.addLayerGroups(originFile, destinationFile, List.of(layoutGrid), layoutParserVersion, layoutParsingTypeName, outline);
        }
    }


    private LayoutGrid createLayoutGrid(Document document, String layoutParserVersion, String layoutParsingType) {

        LayoutGrid layoutGrid = new LayoutGrid();
        layoutGrid.addVersionAndLayoutParsingType(layoutParserVersion, layoutParsingType, document.getFirstPage());

        document.streamAllSubNodes()
                .peek(layoutGrid::addTreeId)
                .forEach(semanticNode -> {
                    switch (semanticNode.getType()) {
                        case SECTION, SUPER_SECTION, TABLE_OF_CONTENTS -> layoutGrid.addSection(semanticNode);
                        case HEADLINE -> layoutGrid.addHeadline((Headline) semanticNode);
                        case PARAGRAPH -> layoutGrid.addParagraph((Paragraph) semanticNode);
                        case TABLE -> layoutGrid.addTable((Table) semanticNode);
                        case IMAGE -> layoutGrid.addImage((Image) semanticNode);
                        case HEADER, FOOTER -> layoutGrid.addHeaderOrFooter(semanticNode);
                        case TABLE_OF_CONTENTS_ITEM -> layoutGrid.addTableOfContentsItem(semanticNode);
                    }
                });
        return layoutGrid;
    }

}
