"""
PromptResolver for resolving template macros.

Implements FR-3: PromptResolver Behavior
"""

from typing import List, Optional

from markitect.prompts.templates.models import PromptTemplate, ContentMacro, MacroKind
from markitect.prompts.resolver.models import (
    ResolutionContext,
    ResolutionResult,
    ResolutionError,
    ResolvedMacro,
)
from markitect.prompts.resolver.strategy import ResolutionStrategy, ResolutionConfig
from markitect.prompts.services.artifact_service import ArtifactService


class PromptResolver:
    """
    Resolver for prompt template macros.

    Implements FR-3: PromptResolver Behavior
    - Deterministic resolution order (FR-3.1)
    - Required macro validation (FR-3.2)
    - Optional macro fallback (FR-3.3)
    - Generate macro detection (FR-3.4)
    """

    def __init__(
        self,
        artifact_service: ArtifactService,
        strategy: ResolutionStrategy,
    ):
        """
        Initialize resolver.

        Args:
            artifact_service: Service for artifact lookup
            strategy: Resolution strategy for search order
        """
        self.artifact_service = artifact_service
        self.strategy = strategy

    def resolve_template(
        self,
        template: PromptTemplate,
        config: ResolutionConfig,
    ) -> ResolutionResult:
        """
        Resolve all macros in a template.

        Implements FR-3: PromptResolver Behavior

        Args:
            template: Template to resolve
            config: Resolution configuration

        Returns:
            ResolutionResult with resolved macros and status

        Raises:
            ValueError: If template hasn't been analyzed
        """
        if not template.analyzed:
            raise ValueError(
                f"Template '{template.name}' must be analyzed before resolution. "
                "Call TemplateAnalyzer.analyze() first."
            )

        # Get search order
        search_order = self.strategy.get_search_order(config)

        # Create resolution context
        context = ResolutionContext(
            template_id=template.id,
            space_id=config.space_id,
            search_order=search_order,
        )

        # Track resolved content and dependencies
        resolved_content = {}
        dependency_artifacts = []

        # Resolve each macro
        for macro in template.macros:
            resolved = self._resolve_macro(macro, search_order, context)

            if resolved.resolved and resolved.artifact:
                resolved_content[macro.target] = resolved.content
                dependency_artifacts.append(resolved.artifact.id)

        # Create result
        result = ResolutionResult(
            context=context,
            success=len(context.unresolved_required) == 0,
            resolved_content=resolved_content,
            dependency_artifacts=dependency_artifacts,
            needs_generation=len(context.generator_macros) > 0,
        )

        return result

    def _resolve_macro(
        self,
        macro: ContentMacro,
        search_order: List[str],
        context: ResolutionContext,
    ) -> ResolvedMacro:
        """
        Resolve a single macro.

        Implements:
        - FR-3.2: Required macro failure
        - FR-3.3: Optional macro empty fallback
        - FR-3.4: Generate macro detection

        Args:
            macro: Macro to resolve
            search_order: Ordered space IDs to search
            context: Resolution context

        Returns:
            ResolvedMacro with resolution result
        """
        # Handle generate macros separately (FR-3.4)
        if macro.kind == MacroKind.GENERATE:
            context.add_generator(macro)
            return ResolvedMacro(
                macro=macro,
                artifact=None,
                resolved=False,  # Will be resolved during generation phase
                space_id=None,
                content="",
            )

        # Try to resolve in each space
        for space_id in search_order:
            artifact = self.artifact_service.repository.get_by_name(
                space_id,
                macro.target,
            )

            if artifact:
                content = artifact.content

                resolved = ResolvedMacro(
                    macro=macro,
                    artifact=artifact,
                    resolved=True,
                    space_id=space_id,
                    content=content,
                )
                context.add_resolved(resolved)
                return resolved

        # Not found in any space
        if macro.kind == MacroKind.REQUIRED:
            # FR-3.2: Required macros fail if not found
            context.add_unresolved_required(macro)
            return ResolvedMacro(
                macro=macro,
                artifact=None,
                resolved=False,
                space_id=None,
                content="",
            )
        else:
            # FR-3.3: Optional macros resolve to empty
            context.add_unresolved_optional(macro)
            return ResolvedMacro(
                macro=macro,
                artifact=None,
                resolved=False,
                space_id=None,
                content="",  # Empty content for optional
            )

    def validate_resolution(self, result: ResolutionResult) -> None:
        """
        Validate resolution result.

        Args:
            result: Resolution result to validate

        Raises:
            ResolutionError: If required macros are missing
        """
        if not result.success:
            unresolved = result.context.unresolved_required
            targets = [m.target for m in unresolved]
            raise ResolutionError(
                f"Failed to resolve required macros: {', '.join(targets)}"
            )

    def get_resolution_summary(self, result: ResolutionResult) -> dict:
        """
        Get human-readable summary of resolution.

        Args:
            result: Resolution result

        Returns:
            Dictionary with summary information
        """
        return {
            "status": result.status.value,
            "success": result.success,
            "resolved_count": len(result.context.resolved_macros),
            "unresolved_required": [
                m.target for m in result.context.unresolved_required
            ],
            "unresolved_optional": [
                m.target for m in result.context.unresolved_optional
            ],
            "needs_generation": result.needs_generation,
            "generator_count": len(result.context.generator_macros),
            "dependency_count": len(result.dependency_artifacts),
            "search_order": result.context.search_order,
        }
