"""
Complex cross-service query operations for prompt infrastructure.

Combines artifact repository, dependency repository, and run data
into higher-level queries like run history, impact analysis, and stats.
"""

from typing import Any, Dict, List, Optional

from markitect.prompts.dependencies.graph import GraphBuilder
from markitect.prompts.dependencies.queries import DependencyQueryService
from markitect.prompts.dependencies.repository import IDependencyRepository
from markitect.prompts.execution.models import PromptRun
from markitect.prompts.incremental.engine import IncrementalExecutionEngine
from markitect.prompts.repositories.interfaces import IArtifactRepository


class PromptQueryService:
    """
    Complex cross-service queries over prompt infrastructure.

    Provides higher-level queries that span multiple data sources:
    run history, stale artifact detection, dependency statistics,
    and content-based artifact lookups.
    """

    def __init__(
        self,
        artifact_repo: IArtifactRepository,
        dependency_repo: IDependencyRepository,
        db_path: Optional[str] = None,
    ):
        """
        Initialize with data sources.

        Args:
            artifact_repo: Artifact repository
            dependency_repo: Dependency edge repository
            db_path: Optional database path for debt queries
        """
        self._artifact_repo = artifact_repo
        self._dependency_repo = dependency_repo
        self._db_path = db_path
        self._query_service = DependencyQueryService(dependency_repo)
        self._graph_builder = GraphBuilder(dependency_repo)
        self._engine = (
            IncrementalExecutionEngine(db_path, self._query_service)
            if db_path
            else None
        )
        # Run registry: external code registers runs for querying
        self._runs: Dict[str, PromptRun] = {}

    def register_run(self, run: PromptRun) -> None:
        """Register a run for query lookups."""
        self._runs[run.id] = run

    def get_run_history(
        self,
        template_id: Optional[str] = None,
        status: Optional[str] = None,
        limit: int = 50,
    ) -> List[Dict[str, Any]]:
        """
        Query run history with optional filters.

        Args:
            template_id: Optional template ID filter
            status: Optional status filter
            limit: Maximum results to return

        Returns:
            List of run dictionaries sorted by start time (newest first)
        """
        runs = list(self._runs.values())

        if template_id:
            runs = [r for r in runs if r.template_id == template_id]

        if status:
            runs = [r for r in runs if r.status.value == status]

        runs.sort(key=lambda r: r.started_at, reverse=True)
        runs = runs[:limit]

        return [r.to_dict() for r in runs]

    def get_stale_artifacts(self) -> List[Dict[str, Any]]:
        """
        Find artifacts with outstanding impact debt.

        Returns:
            List of dicts with artifact info and debt details
        """
        if not self._engine:
            return []

        all_debt = self._engine.get_all_debt()
        if not all_debt:
            return []

        # Group debt by artifact
        debt_by_artifact: Dict[str, list] = {}
        for d in all_debt:
            debt_by_artifact.setdefault(d.artifact_id, []).append(d)

        results = []
        for artifact_id, debts in debt_by_artifact.items():
            artifact = self._artifact_repo.get_by_id(artifact_id)
            results.append({
                "artifact_id": artifact_id,
                "artifact_name": artifact.name if artifact else "unknown",
                "debt_count": len(debts),
                "total_magnitude": sum(d.change_magnitude for d in debts),
                "reasons": list({d.suppression_reason for d in debts}),
            })

        return results

    def get_dependency_stats(self) -> Dict[str, Any]:
        """
        Get summary statistics about the dependency graph.

        Returns:
            Dictionary with graph statistics
        """
        graph = self._graph_builder.build_graph()
        nodes = graph.nodes
        edge_count = graph.edge_count

        # Find root nodes (no predecessors) and leaf nodes (no successors)
        roots = [n for n in nodes if not graph.get_predecessors(n)]
        leaves = [n for n in nodes if not graph.get_successors(n)]

        # Check for cycles
        has_cycles = graph.has_cycle()

        return {
            "total_nodes": len(nodes),
            "total_edges": edge_count,
            "root_count": len(roots),
            "leaf_count": len(leaves),
            "has_cycles": has_cycles,
        }

    def find_artifacts_by_digest(self, digest: str) -> List[Dict[str, Any]]:
        """
        Find all artifacts with a given content digest.

        Args:
            digest: Content digest to search for

        Returns:
            List of artifact dictionaries
        """
        artifacts = self._artifact_repo.get_by_digest(digest)
        return [
            {
                "artifact_id": a.id,
                "name": a.name,
                "space_id": a.space_id,
                "artifact_type": a.artifact_type.value,
            }
            for a in artifacts
        ]
