#!/usr/bin/env python3
"""
Test SSOT XML Templates for Well-Formedness and Compliance

Validates all XML templates in xml-structures/ directory:
- XML well-formedness
- Proper namespace declarations
- Placeholder syntax consistency
- OOXML/ODF compliance
"""

import sys
from lxml import etree as ET
from pathlib import Path
from typing import List, Dict, Set
import re


class SSOTTemplateValidator:
    """Validator for SSOT XML templates"""

    def __init__(self):
        self.errors: List[str] = []
        self.warnings: List[str] = []
        self.placeholders: Set[str] = set()

    def validate_xml_wellformedness(self, xml_path: Path) -> bool:
        """Test XML is well-formed"""
        try:
            with open(xml_path, "r", encoding="utf-8") as f:
                ET.parse(f)
            return True
        except ET.ParseError as e:
            self.errors.append(f"{xml_path.name}: Malformed XML - {e}")
            return False
        except Exception as e:
            self.errors.append(f"{xml_path.name}: Failed to read - {e}")
            return False

    def extract_namespaces(self, xml_path: Path) -> Dict[str, str]:
        """Extract namespace declarations from XML"""
        try:
            with open(xml_path, "r", encoding="utf-8") as f:
                content = f.read()

            # Find all xmlns declarations
            ns_pattern = r'xmlns:?(\w*)\s*=\s*["\']([^"\']+)["\']'
            matches = re.findall(ns_pattern, content)

            namespaces = {}
            for prefix, uri in matches:
                ns_key = prefix if prefix else "default"
                namespaces[ns_key] = uri

            return namespaces
        except Exception as e:
            self.errors.append(f"{xml_path.name}: Failed to extract namespaces - {e}")
            return {}

    def validate_ooxml_namespaces(
        self, xml_path: Path, namespaces: Dict[str, str]
    ) -> bool:
        """Validate OOXML namespace declarations"""
        required_ns = {
            "a": "http://schemas.openxmlformats.org/drawingml/2006/main",
            "r": "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
            "p": "http://schemas.openxmlformats.org/presentationml/2006/main",
            "w": "http://schemas.openxmlformats.org/wordprocessingml/2006/main",
        }

        valid = True
        for prefix, expected_uri in required_ns.items():
            if prefix in namespaces and namespaces[prefix] != expected_uri:
                self.warnings.append(
                    f"{xml_path.name}: Namespace {prefix} has unexpected URI: {namespaces[prefix]}"
                )

        return valid

    def extract_placeholders(self, xml_path: Path) -> Set[str]:
        """Extract all design token placeholders from XML"""
        try:
            with open(xml_path, "r", encoding="utf-8") as f:
                content = f.read()

            # Find all {token.path} placeholders
            placeholder_pattern = r"\{([a-zA-Z_][a-zA-Z0-9_\.]*)\}"
            matches = re.findall(placeholder_pattern, content)

            return set(matches)
        except Exception as e:
            self.errors.append(f"{xml_path.name}: Failed to extract placeholders - {e}")
            return set()

    def validate_placeholder_syntax(
        self, xml_path: Path, placeholders: Set[str]
    ) -> bool:
        """Validate placeholder syntax follows conventions"""
        valid = True

        for placeholder in placeholders:
            # Check placeholder follows dot notation
            if not re.match(
                r"^[a-zA-Z_][a-zA-Z0-9_]*(\.[a-zA-Z_][a-zA-Z0-9_]*)*$", placeholder
            ):
                self.errors.append(
                    f"{xml_path.name}: Invalid placeholder syntax: {{{placeholder}}}"
                )
                valid = False

            # Warn about very deep nesting
            if placeholder.count(".") > 4:
                self.warnings.append(
                    f"{xml_path.name}: Deep nesting in placeholder: {{{placeholder}}}"
                )

        return valid

    def validate_template(self, xml_path: Path) -> bool:
        """Validate a single SSOT XML template"""
        try:
            rel_path = xml_path.relative_to(Path.cwd())
        except ValueError:
            rel_path = xml_path
        print(f"Testing: {rel_path}")

        valid = True

        # Test 1: XML Well-formedness
        if not self.validate_xml_wellformedness(xml_path):
            valid = False
            return valid

        # Test 2: Extract and validate namespaces
        namespaces = self.extract_namespaces(xml_path)
        if "ecma-376" in str(xml_path):
            self.validate_ooxml_namespaces(xml_path, namespaces)

        # Test 3: Extract and validate placeholders
        placeholders = self.extract_placeholders(xml_path)
        self.placeholders.update(placeholders)

        if placeholders:
            print(f"  Found {len(placeholders)} design token placeholders")
            if not self.validate_placeholder_syntax(xml_path, placeholders):
                valid = False

        if valid:
            print("  ✅ Valid")
        else:
            print("  ❌ Failed")

        return valid

    def get_summary(self) -> Dict:
        """Get validation summary"""
        return {
            "total_errors": len(self.errors),
            "total_warnings": len(self.warnings),
            "errors": self.errors,
            "warnings": self.warnings,
            "unique_placeholders": len(self.placeholders),
            "placeholders": sorted(list(self.placeholders)),
        }


def main():
    """Test all SSOT XML templates"""
    print("=" * 80)
    print("SSOT XML Template Validation")
    print("=" * 80)
    print()

    validator = SSOTTemplateValidator()

    # Find all XML templates
    xml_structures = Path("xml-structures")
    if not xml_structures.exists():
        print("❌ Error: xml-structures directory not found")
        return 1

    xml_files = list(xml_structures.rglob("*.xml"))
    print(f"Found {len(xml_files)} XML templates to validate\n")

    # Validate each template
    all_valid = True
    for xml_file in sorted(xml_files):
        if not validator.validate_template(xml_file):
            all_valid = False
        print()

    # Print summary
    summary = validator.get_summary()

    print("=" * 80)
    print("VALIDATION SUMMARY")
    print("=" * 80)
    print()

    if all_valid:
        print("✅ All templates passed validation")
    else:
        print("❌ Some templates failed validation")

    print("\nStatistics:")
    print(f"  Total templates: {len(xml_files)}")
    print(f"  Errors: {summary['total_errors']}")
    print(f"  Warnings: {summary['total_warnings']}")
    print(f"  Unique placeholders: {summary['unique_placeholders']}")

    if summary["errors"]:
        print("\nErrors:")
        for error in summary["errors"]:
            print(f"  • {error}")

    if summary["warnings"]:
        print("\nWarnings:")
        for warning in summary["warnings"]:
            print(f"  • {warning}")

    if summary["placeholders"]:
        print("\nDesign Token Placeholders Found:")
        # Group by category
        by_category = {}
        for placeholder in summary["placeholders"]:
            category = placeholder.split(".")[0]
            if category not in by_category:
                by_category[category] = []
            by_category[category].append(placeholder)

        for category in sorted(by_category.keys()):
            print(f"\n  {category}:")
            for placeholder in sorted(by_category[category]):
                print(f"    - {placeholder}")

    print()
    return 0 if all_valid else 1


if __name__ == "__main__":
    sys.exit(main())
