package com.knecon.fforesight.service.layoutparser.server.graph;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

import org.junit.jupiter.api.Test;

import com.knecon.fforesight.service.layoutparser.internal.api.data.redaction.DocumentData;
import com.knecon.fforesight.service.layoutparser.internal.api.data.redaction.DocumentPage;
import com.knecon.fforesight.service.layoutparser.internal.api.data.redaction.DocumentPositionData;
import com.knecon.fforesight.service.layoutparser.internal.api.data.redaction.DocumentStructure;
import com.knecon.fforesight.service.layoutparser.internal.api.data.redaction.DocumentTextData;
import com.knecon.fforesight.service.layoutparser.internal.api.data.redaction.NodeType;
import com.knecon.fforesight.service.layoutparser.processor.model.graph.nodes.Document;
import com.knecon.fforesight.service.layoutparser.processor.model.graph.nodes.Table;
import com.knecon.fforesight.service.layoutparser.processor.services.mapper.DocumentDataMapper;
import com.knecon.fforesight.service.layoutparser.processor.services.mapper.DocumentGraphMapper;
import com.knecon.fforesight.service.layoutparser.processor.services.mapper.PropertiesMapper;
import com.knecon.fforesight.service.layoutparser.server.utils.BuildDocumentTest;
import com.knecon.fforesight.tenantcommons.TenantContext;

import lombok.SneakyThrows;

public class DocumentGraphMappingTest extends BuildDocumentTest {

    @Test
    @SneakyThrows
    public void testGraphMapping() {

        String filename = "files/syngenta/CustomerFiles/SYNGENTA_EFSA_sanitisation_GFL_v1_moreSections.pdf";

        Document document = buildGraph(filename);
        DocumentData documentData = DocumentDataMapper.toDocumentData(document);

        storageService.storeJSONObject(TenantContext.getTenantId(), filename + "_PAGES" + ".json", documentData.getDocumentPages());
        storageService.storeJSONObject(TenantContext.getTenantId(), filename + "_TEXT" + ".json", documentData.getDocumentTextData());
        storageService.storeJSONObject(TenantContext.getTenantId(), filename + "_POSITIONS" + ".json", documentData.getDocumentPositions());
        storageService.storeJSONObject(TenantContext.getTenantId(), filename + "_STRUCTURE" + ".json", documentData.getDocumentStructure());

        DocumentPage[] pageData = storageService.readJSONObject(TenantContext.getTenantId(), filename + "_PAGES" + ".json", DocumentPage[].class);
        DocumentTextData[] atomicTextBlockData = storageService.readJSONObject(TenantContext.getTenantId(), filename + "_TEXT" + ".json", DocumentTextData[].class);
        DocumentPositionData[] atomicPositionBlockData = storageService.readJSONObject(TenantContext.getTenantId(),
                filename + "_POSITIONS" + ".json",
                DocumentPositionData[].class);
        DocumentStructure documentTreeData = storageService.readJSONObject(TenantContext.getTenantId(), filename + "_STRUCTURE" + ".json", DocumentStructure.class);

        DocumentData documentData2 = DocumentData.builder()
                .documentPages(pageData)
                .documentStructure(documentTreeData)
                .documentTextData(atomicTextBlockData)
                .documentPositions(atomicPositionBlockData)
                .build();
        Document newDocument = DocumentGraphMapper.toDocumentGraph(documentData2);

        assertTrue(allTablesHavePositiveNumberOfRowsAndColumns(document));
        assertTrue(allTablesHavePositiveNumberOfRowsAndColumns(documentData));
        assertTrue(allTablesHavePositiveNumberOfRowsAndColumns(documentData2));
        assertTrue(allTablesHavePositiveNumberOfRowsAndColumns(newDocument));

        assertEquals(document.toString(), newDocument.toString());
        assertEquals(document.getDocumentTree().toString(), newDocument.getDocumentTree().toString());
    }


    private static boolean allTablesHavePositiveNumberOfRowsAndColumns(Document document) {

        return document.streamAllSubNodes()
                .filter(semanticNode -> semanticNode instanceof Table)
                .map(semanticNode -> (Table) semanticNode)
                .allMatch(tableNode -> tableNode.getNumberOfCols() > 0 && tableNode.getNumberOfRows() > 0);
    }


    private static boolean allTablesHavePositiveNumberOfRowsAndColumns(DocumentData documentData) {

        return documentData.getDocumentStructure()
                .streamAllEntries()
                .filter(entryData -> entryData.getType().equals(NodeType.TABLE))
                .map(DocumentStructure.EntryData::getProperties)
                .map(properties -> {
                    var builder = Table.builder();
                    PropertiesMapper.parseTableProperties(properties, builder);
                    return builder.build();
                })
                .allMatch(tableNode -> tableNode.getNumberOfCols() > 0 && tableNode.getNumberOfRows() > 0);
    }

}
