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.iqser.red.service.redaction.v1.server.data.DocumentData;
import com.iqser.red.service.redaction.v1.server.data.DocumentPageProto;
import com.iqser.red.service.redaction.v1.server.data.DocumentPositionDataProto;
import com.iqser.red.service.redaction.v1.server.data.DocumentStructureProto;
import com.iqser.red.service.redaction.v1.server.data.DocumentStructureWrapper;
import com.iqser.red.service.redaction.v1.server.data.DocumentTextDataProto;
import com.iqser.red.service.redaction.v1.server.data.EntryDataProto;
import com.iqser.red.service.redaction.v1.server.data.NodeTypeProto;
import com.iqser.red.service.redaction.v1.server.mapper.DocumentDataMapper;
import com.iqser.red.service.redaction.v1.server.mapper.DocumentGraphMapper;
import com.iqser.red.service.redaction.v1.server.mapper.PropertiesMapper;
import com.iqser.red.service.redaction.v1.server.model.document.nodes.Document;
import com.iqser.red.service.redaction.v1.server.model.document.nodes.Table;
import com.knecon.fforesight.service.layoutparser.server.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.storeProtoObject(TenantContext.getTenantId(), filename + "_PAGES" + ".proto", documentData.getDocumentPages());
        storageService.storeProtoObject(TenantContext.getTenantId(), filename + "_TEXT" + ".proto", documentData.getDocumentTextData());
        storageService.storeProtoObject(TenantContext.getTenantId(), filename + "_POSITIONS" + ".proto", documentData.getDocumentPositionData());
        storageService.storeProtoObject(TenantContext.getTenantId(), filename + "_STRUCTURE" + ".proto", documentData.getDocumentStructure());

        DocumentPageProto.AllDocumentPages pageData = storageService.readProtoObject(TenantContext.getTenantId(),
                                                                                     filename + "_PAGES" + ".proto",
                                                                                     DocumentPageProto.AllDocumentPages.parser());
        DocumentTextDataProto.AllDocumentTextData atomicTextBlockData = storageService.readProtoObject(TenantContext.getTenantId(),
                                                                                                       filename + "_TEXT" + ".proto",
                                                                                                       DocumentTextDataProto.AllDocumentTextData.parser());
        DocumentPositionDataProto.AllDocumentPositionData atomicPositionBlockData = storageService.readProtoObject(TenantContext.getTenantId(),
                                                                                                                   filename + "_POSITIONS" + ".proto",
                                                                                                                   DocumentPositionDataProto.AllDocumentPositionData.parser());
        DocumentStructureProto.DocumentStructure documentTreeData = storageService.readProtoObject(TenantContext.getTenantId(),
                                                                                                   filename + "_STRUCTURE" + ".proto",
                                                                                                   DocumentStructureProto.DocumentStructure.parser());

        DocumentData documentData2 = DocumentData.builder()
                .documentPages(pageData)
                .documentStructureWrapper(new DocumentStructureWrapper(documentTreeData))
                .documentTextData(atomicTextBlockData)
                .documentPositionData(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.getDocumentStructureWrapper().streamAllEntries()
                .filter(entryData -> entryData.getType().equals(NodeTypeProto.NodeType.TABLE))
                .map(EntryDataProto.EntryData::getPropertiesMap)
                .map(properties -> {
                    var builder = Table.builder();
                    PropertiesMapper.parseTableProperties(properties, builder);
                    return builder.build();
                })
                .allMatch(tableNode -> tableNode.getNumberOfCols() > 0 && tableNode.getNumberOfRows() > 0);
    }

}
