"""Ground Tracker — records every run's benchmark, constraints, path outcomes, learnings.
PCT Components 11-12: Expanded Ground, Permanent Experiment."""

from dataclasses import dataclass, field
from datetime import datetime
from typing import Any
from uuid import UUID, uuid4

from xyglue.thinking.models import ThinkingResult


@dataclass
class GroundRecord:
    """A single ground record from one run."""

    id: UUID = field(default_factory=uuid4)
    run_id: UUID = field(default_factory=uuid4)
    goal_text: str = ""
    benchmark_domain: str = ""
    benchmark_elements: list[dict] = field(default_factory=list)
    physics_constraints: list[dict] = field(default_factory=list)
    habit_constraints: list[dict] = field(default_factory=list)
    path_attempted: list[str] = field(default_factory=list)
    winning_path: str = ""
    paths_data: dict[str, dict] = field(default_factory=dict)
    failed_path_learnings: list[dict] = field(default_factory=list)
    reclassified_constraints: list[dict] = field(default_factory=list)
    quality_score: float = 0.0
    was_healed: bool = False
    heal_count: int = 0
    created_at: datetime = field(default_factory=datetime.utcnow)

    def to_dict(self) -> dict[str, Any]:
        return {
            "id": str(self.id),
            "run_id": str(self.run_id),
            "goal_text": self.goal_text,
            "benchmark_domain": self.benchmark_domain,
            "winning_path": self.winning_path,
            "path_attempted": self.path_attempted,
            "quality_score": self.quality_score,
            "was_healed": self.was_healed,
            "heal_count": self.heal_count,
        }


class GroundTracker:
    def __init__(self) -> None:
        self._records: list[GroundRecord] = []
        self._domain_knowledge: dict[str, list[GroundRecord]] = {}

    def record(
        self,
        run_id: UUID,
        thinking_result: ThinkingResult,
        winning_path: str,
        paths_attempted: list[str],
        quality_score: float,
        was_healed: bool,
        heal_count: int,
        failed_learnings: list[dict] | None = None,
        reclassified: list[dict] | None = None,
    ) -> GroundRecord:
        record = GroundRecord(
            run_id=run_id,
            goal_text=thinking_result.goal_text,
            benchmark_domain=thinking_result.benchmark_map.domain,
            benchmark_elements=[
                e.to_dict() for e in thinking_result.benchmark_map.elements
            ],
            physics_constraints=[
                c.to_dict() for c in thinking_result.classified_map.get_physics()
            ],
            habit_constraints=[
                c.to_dict() for c in thinking_result.classified_map.get_habits()
            ],
            path_attempted=paths_attempted,
            winning_path=winning_path,
            paths_data={p.id: p.to_dict() for p in thinking_result.paths},
            failed_path_learnings=failed_learnings or [],
            reclassified_constraints=reclassified or [],
            quality_score=quality_score,
            was_healed=was_healed,
            heal_count=heal_count,
        )
        self._records.append(record)
        domain = record.benchmark_domain
        if domain not in self._domain_knowledge:
            self._domain_knowledge[domain] = []
        self._domain_knowledge[domain].append(record)
        return record

    def find_similar(self, domain: str, limit: int = 5) -> list[GroundRecord]:
        return self._domain_knowledge.get(domain, [])[:limit]

    def get_stats(self) -> dict[str, Any]:
        total = len(self._records)
        if total == 0:
            return {"total_runs": 0}
        return {
            "total_runs": total,
            "domains_mapped": len(self._domain_knowledge),
            "avg_quality": sum(r.quality_score for r in self._records) / total,
            "path_a_wins": sum(
                1 for r in self._records if r.winning_path == "A"
            ),
            "path_b_wins": sum(
                1 for r in self._records if r.winning_path == "B"
            ),
            "path_c_wins": sum(
                1 for r in self._records if r.winning_path == "C"
            ),
            "healed_runs": sum(1 for r in self._records if r.was_healed),
        }
