package at.procon.ted.service;

import at.procon.ted.model.entity.*;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.DisplayName;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;

import static org.junit.jupiter.api.Assertions.*;

/**
 * Unit tests for XmlParserService.
 * 
 * @author Martin.Schweitzer@procon.co.at and claude.ai
 */
class XmlParserServiceTest {

    private XmlParserService parserService;

    @BeforeEach
    void setUp() {
        parserService = new XmlParserService();
    }

    @Test
    @DisplayName("Should parse contract notice XML and extract basic metadata")
    void testParseContractNotice() {
        // Sample minimal eForms XML
        String xml = """
                <?xml version="1.0" encoding="UTF-8"?>
                <ContractNotice xmlns="urn:oasis:names:specification:ubl:schema:xsd:ContractNotice-2"
                    xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2"
                    xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2">
                    <cbc:UBLVersionID>2.3</cbc:UBLVersionID>
                    <cbc:CustomizationID>eforms-sdk-1.13</cbc:CustomizationID>
                    <cbc:ID schemeName="notice-id">test-notice-123</cbc:ID>
                    <cbc:IssueDate>2025-01-15</cbc:IssueDate>
                    <cbc:NoticeTypeCode listName="competition">cn-standard</cbc:NoticeTypeCode>
                    <cbc:NoticeLanguageCode>ENG</cbc:NoticeLanguageCode>
                    <cac:ProcurementProject>
                        <cbc:Name languageID="ENG">Test Procurement Project</cbc:Name>
                        <cbc:Description languageID="ENG">This is a test description</cbc:Description>
                        <cbc:ProcurementTypeCode listName="contract-nature">supplies</cbc:ProcurementTypeCode>
                    </cac:ProcurementProject>
                    <cac:TenderingProcess>
                        <cbc:ProcedureCode listName="procurement-procedure-type">open</cbc:ProcedureCode>
                    </cac:TenderingProcess>
                </ContractNotice>
                """;

        ProcurementDocument document = parserService.parseDocument(xml);

        assertNotNull(document);
        assertEquals("2.3", document.getUblVersion());
        assertEquals("eforms-sdk-1.13", document.getSdkVersion());
        assertEquals("test-notice-123", document.getNoticeId());
        assertEquals(NoticeType.CONTRACT_NOTICE, document.getNoticeType());
        assertEquals("ENG", document.getLanguageCode());
        assertEquals("Test Procurement Project", document.getProjectTitle());
        assertEquals("This is a test description", document.getProjectDescription());
        assertEquals(ContractNature.SUPPLIES, document.getContractNature());
        assertEquals(ProcedureType.OPEN, document.getProcedureType());
    }

    @Test
    @DisplayName("Should extract CPV codes from procurement project")
    void testParseCpvCodes() {
        String xml = """
                <?xml version="1.0" encoding="UTF-8"?>
                <ContractNotice xmlns="urn:oasis:names:specification:ubl:schema:xsd:ContractNotice-2"
                    xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2"
                    xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2">
                    <cbc:UBLVersionID>2.3</cbc:UBLVersionID>
                    <cac:ProcurementProject>
                        <cbc:Name languageID="ENG">Medical Supplies</cbc:Name>
                        <cbc:ProcurementTypeCode>supplies</cbc:ProcurementTypeCode>
                        <cac:MainCommodityClassification>
                            <cbc:ItemClassificationCode listName="cpv">33140000</cbc:ItemClassificationCode>
                        </cac:MainCommodityClassification>
                        <cac:AdditionalCommodityClassification>
                            <cbc:ItemClassificationCode listName="cpv">33141000</cbc:ItemClassificationCode>
                        </cac:AdditionalCommodityClassification>
                    </cac:ProcurementProject>
                </ContractNotice>
                """;

        ProcurementDocument document = parserService.parseDocument(xml);

        assertNotNull(document.getCpvCodes());
        assertEquals(2, document.getCpvCodes().length);
        assertEquals("33140000", document.getCpvCodes()[0]);
        assertEquals("33141000", document.getCpvCodes()[1]);
    }

    @Test
    @DisplayName("Should generate text content for vectorization")
    void testTextContentGeneration() {
        String xml = """
                <?xml version="1.0" encoding="UTF-8"?>
                <ContractNotice xmlns="urn:oasis:names:specification:ubl:schema:xsd:ContractNotice-2"
                    xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2"
                    xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2">
                    <cbc:UBLVersionID>2.3</cbc:UBLVersionID>
                    <cac:ProcurementProject>
                        <cbc:Name languageID="ENG">Hospital Equipment Procurement</cbc:Name>
                        <cbc:Description languageID="ENG">Procurement of medical imaging equipment</cbc:Description>
                        <cbc:ProcurementTypeCode>supplies</cbc:ProcurementTypeCode>
                    </cac:ProcurementProject>
                </ContractNotice>
                """;

        ProcurementDocument document = parserService.parseDocument(xml);

        assertNotNull(document.getTextContent());
        assertTrue(document.getTextContent().contains("Hospital Equipment Procurement"));
        assertTrue(document.getTextContent().contains("medical imaging equipment"));
    }

    @Test
    @DisplayName("Should handle missing optional fields gracefully")
    void testMissingOptionalFields() {
        String xml = """
                <?xml version="1.0" encoding="UTF-8"?>
                <ContractNotice xmlns="urn:oasis:names:specification:ubl:schema:xsd:ContractNotice-2"
                    xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2">
                    <cbc:UBLVersionID>2.3</cbc:UBLVersionID>
                </ContractNotice>
                """;

        ProcurementDocument document = parserService.parseDocument(xml);

        assertNotNull(document);
        assertEquals("2.3", document.getUblVersion());
        assertNull(document.getProjectTitle());
        assertNull(document.getPublicationId());
        assertEquals(NoticeType.OTHER, document.getNoticeType());
    }

    @Test
    @DisplayName("Should throw exception for invalid XML")
    void testInvalidXml() {
        String invalidXml = "This is not XML";

        assertThrows(XmlParserService.XmlParsingException.class, () -> {
            parserService.parseDocument(invalidXml);
        });
    }

    @Test
    @DisplayName("Should store original XML document")
    void testXmlDocumentStorage() {
        String xml = """
                <?xml version="1.0" encoding="UTF-8"?>
                <ContractNotice xmlns="urn:oasis:names:specification:ubl:schema:xsd:ContractNotice-2"
                    xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2">
                    <cbc:UBLVersionID>2.3</cbc:UBLVersionID>
                </ContractNotice>
                """;

        ProcurementDocument document = parserService.parseDocument(xml);

        assertNotNull(document.getXmlDocument());
        assertEquals(xml, document.getXmlDocument());
    }

    @Test
    @DisplayName("Should map contract nature correctly")
    void testContractNatureMapping() {
        String[] natures = {"supplies", "services", "works", "mixed", "unknown"};
        ContractNature[] expected = {
            ContractNature.SUPPLIES, 
            ContractNature.SERVICES, 
            ContractNature.WORKS, 
            ContractNature.MIXED, 
            ContractNature.UNKNOWN
        };

        for (int i = 0; i < natures.length; i++) {
            String xml = String.format("""
                    <?xml version="1.0" encoding="UTF-8"?>
                    <ContractNotice xmlns="urn:oasis:names:specification:ubl:schema:xsd:ContractNotice-2"
                        xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2"
                        xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2">
                        <cbc:UBLVersionID>2.3</cbc:UBLVersionID>
                        <cac:ProcurementProject>
                            <cbc:ProcurementTypeCode>%s</cbc:ProcurementTypeCode>
                        </cac:ProcurementProject>
                    </ContractNotice>
                    """, natures[i]);

            ProcurementDocument document = parserService.parseDocument(xml);
            assertEquals(expected[i], document.getContractNature(), 
                    "Failed for nature: " + natures[i]);
        }
    }
}
