"""
Template analyzer for dependency extraction.

Implements FR-2.2: TemplateAnalysis
Analyzes templates to extract and catalog content macros.
"""

from typing import List, Set

from markitect.prompts.templates.models import PromptTemplate, MacroKind
from markitect.prompts.templates.parser import MacroParser


class TemplateAnalysisResult:
    """
    Result of template analysis.

    Provides summary information about template dependencies.

    Attributes:
        template: Analyzed template
        total_macros: Total number of macros found
        required_count: Number of required macros
        optional_count: Number of optional macros
        generate_count: Number of generate macros
        unique_targets: Set of unique target names
        has_circular_potential: Whether template references itself
    """

    def __init__(self, template: PromptTemplate):
        self.template = template
        self.total_macros = len(template.macros)
        self.required_count = len(template.get_required_dependencies())
        self.optional_count = len(template.get_optional_dependencies())
        self.generate_count = len(template.get_generators())
        self.unique_targets = self._get_unique_targets()
        self.has_circular_potential = template.name in self.unique_targets

    def _get_unique_targets(self) -> Set[str]:
        """Get set of unique target names from all macros."""
        return {macro.target for macro in self.template.macros}

    def to_dict(self) -> dict:
        """Convert result to dictionary."""
        return {
            "template_id": self.template.id,
            "template_name": self.template.name,
            "total_macros": self.total_macros,
            "required_count": self.required_count,
            "optional_count": self.optional_count,
            "generate_count": self.generate_count,
            "unique_targets": list(self.unique_targets),
            "has_circular_potential": self.has_circular_potential,
        }


class TemplateAnalyzer:
    """
    Analyzer for extracting dependencies from templates.

    Implements FR-2.2: TemplateAnalysis
    Uses MacroParser to detect and extract ContentMacros, then populates
    the template's macro list and provides analysis results.
    """

    def __init__(self):
        self.parser = MacroParser()

    def analyze(self, template: PromptTemplate, content: str) -> TemplateAnalysisResult:
        """
        Analyze template content and extract macros.

        Updates the template's macros list and marks it as analyzed.

        Args:
            template: Template to analyze
            content: Template content to parse

        Returns:
            Analysis result with summary information

        Raises:
            MacroParsingError: If macro syntax is invalid
        """
        # Parse macros from content
        macros = self.parser.parse(content)

        # Update template
        template.macros = macros
        template.analyzed = True

        # Create and return analysis result
        return TemplateAnalysisResult(template)

    def quick_check(self, content: str) -> dict:
        """
        Quick check of template content without full analysis.

        Useful for validation before template creation.

        Args:
            content: Template content

        Returns:
            Dictionary with macro counts and basic info
        """
        has_macros = self.parser.has_macros(content)
        if not has_macros:
            return {
                "has_macros": False,
                "required": 0,
                "optional": 0,
                "generate": 0,
                "total": 0,
            }

        counts = self.parser.count_macros(content)
        return {
            "has_macros": True,
            "required": counts['required'],
            "optional": counts['optional'],
            "generate": counts['generate'],
            "total": sum(counts.values()),
        }

    def find_dependencies(self, template: PromptTemplate) -> dict:
        """
        Extract dependency information from analyzed template.

        Args:
            template: Analyzed template

        Returns:
            Dictionary with categorized dependencies

        Raises:
            ValueError: If template has not been analyzed
        """
        if not template.analyzed:
            raise ValueError(
                f"Template '{template.name}' has not been analyzed. "
                "Call analyze() first."
            )

        return {
            "required": template.get_required_dependencies(),
            "optional": template.get_optional_dependencies(),
            "generators": template.get_generators(),
            "all_targets": list({m.target for m in template.macros}),
        }

    def validate_references(
        self,
        template: PromptTemplate,
        available_artifacts: Set[str],
    ) -> dict:
        """
        Validate that template references can be resolved.

        Args:
            template: Template to validate
            available_artifacts: Set of available artifact names

        Returns:
            Dictionary with validation results:
                - missing_required: List of missing required artifacts
                - missing_optional: List of missing optional artifacts
                - missing_generators: List of missing generator templates
                - is_valid: True if all required deps are available

        Raises:
            ValueError: If template has not been analyzed
        """
        if not template.analyzed:
            raise ValueError(
                f"Template '{template.name}' has not been analyzed. "
                "Call analyze() first."
            )

        required = set(template.get_required_dependencies())
        optional = set(template.get_optional_dependencies())
        generators = set(template.get_generators())

        missing_required = required - available_artifacts
        missing_optional = optional - available_artifacts
        missing_generators = generators - available_artifacts

        return {
            "missing_required": list(missing_required),
            "missing_optional": list(missing_optional),
            "missing_generators": list(missing_generators),
            "is_valid": len(missing_required) == 0,
        }
