"""
Test suite for XML Structure Enumeration System (Task 1)
Tests namespace-aware XML parsing, structure traversal, and format analysis.
"""

import pytest
import tempfile
import zipfile
from pathlib import Path

import sys

sys.path.insert(0, str(Path(__file__).parent.parent / "src"))

from tokenmoulds.verification.xml_parser import XMLParser
from tokenmoulds.verification.structure_analyzer import StructureAnalyzer
from tokenmoulds.verification.format_detector import FormatDetector, OfficeFormat


class TestXMLParserFramework:
    """Test namespace-aware XML parsing with dual-engine support."""

    def setup_method(self):
        """Setup test fixtures."""
        self.sample_ooxml = """<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<a:theme xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" name="Test Theme">
  <a:themeElements>
    <a:clrScheme name="TestScheme">
      <a:dk1><a:sysClr val="windowText" lastClr="000000"/></a:dk1>
      <a:accent1><a:srgbClr val="{{color.brand.primary}}"/></a:accent1>
    </a:clrScheme>
  </a:themeElements>
</a:theme>"""

        self.sample_odf = """<?xml version="1.0" encoding="UTF-8"?>
<office:document-styles xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0"
                       xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0"
                       xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0">
  <office:styles>
    <style:style style:name="Standard" style:family="paragraph">
      <style:text-properties fo:color="{{color.text.primary}}"/>
    </style:style>
  </office:styles>
</office:document-styles>"""

    def test_lxml_namespace_parsing(self):
        """Test lxml parser handles OOXML namespaces correctly."""
        parser = XMLParser(engine="lxml")
        root = parser.parse_string(self.sample_ooxml)

        # Test namespace-aware element access
        namespaces = {"a": "http://schemas.openxmlformats.org/drawingml/2006/main"}
        theme_elements = root.xpath("//a:themeElements", namespaces=namespaces)
        assert len(theme_elements) == 1

        # Test token placeholder detection
        accent_elements = root.xpath(
            "//a:accent1/a:srgbClr/@val", namespaces=namespaces
        )
        assert accent_elements[0] == "{{color.brand.primary}}"

    def test_elementtree_namespace_parsing(self):
        """Test ElementTree parser handles OOXML namespaces correctly."""
        parser = XMLParser(engine="elementtree")
        root = parser.parse_string(self.sample_ooxml)

        # Test namespace registration and access
        ns = {"a": "http://schemas.openxmlformats.org/drawingml/2006/main"}
        theme_elements = root.findall(".//a:themeElements", ns)
        assert len(theme_elements) == 1

    def test_odf_namespace_parsing(self):
        """Test ODF namespace handling with both engines."""
        parser_lxml = XMLParser(engine="lxml")
        parser_et = XMLParser(engine="elementtree")

        root_lxml = parser_lxml.parse_string(self.sample_odf)
        root_et = parser_et.parse_string(self.sample_odf)

        # Both engines should handle ODF namespaces
        assert root_lxml is not None
        assert root_et is not None

    def test_token_placeholder_extraction(self):
        """Test extraction of token placeholders from XML content."""
        parser = XMLParser(engine="lxml")
        placeholders = parser.extract_token_placeholders(self.sample_ooxml)

        expected_tokens = ["{{color.brand.primary}}"]
        assert placeholders == expected_tokens

    def test_dual_engine_consistency(self):
        """Test that both XML engines produce consistent results."""
        parser_lxml = XMLParser(engine="lxml")
        parser_et = XMLParser(engine="elementtree")

        tokens_lxml = parser_lxml.extract_token_placeholders(self.sample_ooxml)
        tokens_et = parser_et.extract_token_placeholders(self.sample_ooxml)

        assert tokens_lxml == tokens_et


class TestStructureTraversal:
    """Test systematic XML structure traversal and cataloging."""

    def test_element_enumeration(self):
        """Test enumeration of all XML elements in a structure."""
        analyzer = StructureAnalyzer()

        with tempfile.NamedTemporaryFile(mode="w", suffix=".xml", delete=False) as f:
            f.write("""<?xml version="1.0"?>
<root xmlns:a="http://test.com/a" xmlns:b="http://test.com/b">
  <a:element1 attr1="value1">
    <b:nested attr2="{{token.test}}"/>
  </a:element1>
</root>""")
            f.flush()

            structure = analyzer.analyze_file(Path(f.name))

            # Should catalog all elements with namespaces and attributes
            assert "root" in structure.elements
            assert "{http://test.com/a}element1" in structure.elements
            assert "{http://test.com/b}nested" in structure.elements

            # Should track attributes and token placeholders
            # Check that attributes are tracked per element
            root_element = structure.elements.get("root")
            element1 = structure.elements.get("{http://test.com/a}element1")
            nested = structure.elements.get("{http://test.com/b}nested")

            assert root_element is not None
            assert element1 is not None
            assert nested is not None
            assert "attr1" in element1.attributes
            assert "attr2" in nested.attributes
            assert "{{token.test}}" in structure.token_placeholders

    def test_zip_file_analysis(self):
        """Test analysis of XML structures within ZIP archives (Office files)."""
        analyzer = StructureAnalyzer()

        sample_theme_xml = """<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<a:theme xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" name="Test Theme">
  <a:themeElements>
    <a:clrScheme name="TestScheme">
      <a:accent1><a:srgbClr val="{{color.brand.primary}}"/></a:accent1>
    </a:clrScheme>
  </a:themeElements>
</a:theme>"""

        # Create a mock .potx file structure
        with tempfile.TemporaryDirectory() as temp_dir:
            temp_path = Path(temp_dir)
            zip_path = temp_path / "test.potx"

            with zipfile.ZipFile(zip_path, "w") as zf:
                zf.writestr("ppt/theme/theme1.xml", sample_theme_xml)
                zf.writestr("[Content_Types].xml", '<?xml version="1.0"?><Types/>')

            structure = analyzer.analyze_zip_file(zip_path)

            # Should analyze XML files within the ZIP
            assert len(structure.xml_files) >= 1
            assert "ppt/theme/theme1.xml" in structure.xml_files


class TestFormatDetection:
    """Test detection and classification of OOXML and ODF formats."""

    def test_ooxml_format_detection(self):
        """Test detection of OOXML formats (.potx, .dotx, .xltx)."""
        detector = FormatDetector()

        # Test file extension detection
        assert (
            detector.detect_format(Path("test.potx"))
            == OfficeFormat.POWERPOINT_TEMPLATE
        )
        assert detector.detect_format(Path("test.dotx")) == OfficeFormat.WORD_TEMPLATE
        assert detector.detect_format(Path("test.xltx")) == OfficeFormat.EXCEL_TEMPLATE

    def test_odf_format_detection(self):
        """Test detection of ODF formats (.otp, .ott, .ots)."""
        detector = FormatDetector()

        assert detector.detect_format(Path("test.otp")) == OfficeFormat.IMPRESS_TEMPLATE
        assert detector.detect_format(Path("test.ott")) == OfficeFormat.WRITER_TEMPLATE
        assert detector.detect_format(Path("test.ots")) == OfficeFormat.CALC_TEMPLATE

    def test_content_types_analysis(self):
        """Test analysis of [Content_Types].xml for format verification."""
        detector = FormatDetector()

        content_types_xml = """<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
  <Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>
  <Override PartName="/ppt/presentation.xml" ContentType="application/vnd.openxmlformats-presentationml.presentation.main+xml"/>
</Types>"""

        format_info = detector.analyze_content_types(content_types_xml)
        assert format_info.primary_format == "presentation"
        # Check for the exact content type, not partial string
        assert any(
            "presentationml.presentation.main" in ct for ct in format_info.content_types
        )


if __name__ == "__main__":
    pytest.main([__file__])
