"""Template Library — proven templates only. 0.95 threshold, 2-3x proven.
A library of 50 proven templates > a library of 5,000 unvalidated ones."""

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 TemplateCandidate:
    id: UUID = field(default_factory=uuid4)
    thinking_result_dict: dict[str, Any] = field(default_factory=dict)
    goal_text: str = ""
    domain: str = ""
    winning_path: str = ""
    quality_scores: list[float] = field(default_factory=list)
    validation_count: int = 0
    last_failure: datetime | None = None
    created_at: datetime = field(default_factory=datetime.utcnow)

    def add_score(self, score: float, threshold: float) -> bool:
        if score >= threshold:
            self.quality_scores.append(score)
            self.validation_count += 1
            return True
        else:
            self.quality_scores = []
            self.validation_count = 0
            self.last_failure = datetime.utcnow()
            return False


@dataclass
class ProvenTemplate:
    id: UUID = field(default_factory=uuid4)
    goal_text: str = ""
    domain: str = ""
    thinking_result_dict: dict[str, Any] = field(default_factory=dict)
    winning_path: str = ""
    avg_quality_score: float = 0.0
    validation_scores: list[float] = field(default_factory=list)
    times_used: int = 0
    domain_tags: list[str] = field(default_factory=list)
    created_at: datetime = field(default_factory=datetime.utcnow)

    def to_dict(self) -> dict[str, Any]:
        return {
            "id": str(self.id),
            "goal_text": self.goal_text,
            "domain": self.domain,
            "winning_path": self.winning_path,
            "avg_quality_score": self.avg_quality_score,
            "times_used": self.times_used,
        }


class TemplateLibrary:
    """
    VALIDATION RULES:
    - Quality >= 0.95 / 1.0
    - Must score >=0.95 on 2-3 SEPARATE runs
    - Single failure resets validation counter
    """

    def __init__(
        self,
        quality_threshold: float = 0.95,
        proven_count: int = 2,
        failure_resets: bool = True,
    ) -> None:
        self.quality_threshold = quality_threshold
        self.proven_count = proven_count
        self.failure_resets = failure_resets
        self._candidates: dict[str, TemplateCandidate] = {}
        self._templates: dict[UUID, ProvenTemplate] = {}
        self._domain_index: dict[str, list[UUID]] = {}

    def submit_candidate(
        self,
        thinking_result: ThinkingResult,
        winning_path: str,
        quality_score: float,
    ) -> str:
        """Returns: 'promoted' | 'validating' | 'rejected' | 'reset'"""
        key = self._make_key(
            thinking_result.benchmark_map.domain, thinking_result.goal_text
        )

        if key not in self._candidates:
            if quality_score < self.quality_threshold:
                return "rejected"
            self._candidates[key] = TemplateCandidate(
                thinking_result_dict=thinking_result.to_dict(),
                goal_text=thinking_result.goal_text,
                domain=thinking_result.benchmark_map.domain,
                winning_path=winning_path,
            )
            self._candidates[key].add_score(quality_score, self.quality_threshold)
            return "validating"

        candidate = self._candidates[key]
        passed = candidate.add_score(quality_score, self.quality_threshold)
        if not passed:
            return "reset"

        if candidate.validation_count >= self.proven_count:
            template = ProvenTemplate(
                goal_text=candidate.goal_text,
                domain=candidate.domain,
                thinking_result_dict=candidate.thinking_result_dict,
                winning_path=candidate.winning_path,
                avg_quality_score=(
                    sum(candidate.quality_scores) / len(candidate.quality_scores)
                ),
                validation_scores=candidate.quality_scores.copy(),
                domain_tags=[candidate.domain],
            )
            self._templates[template.id] = template
            if template.domain not in self._domain_index:
                self._domain_index[template.domain] = []
            self._domain_index[template.domain].append(template.id)
            del self._candidates[key]
            return "promoted"
        return "validating"

    def find_templates(
        self, domain: str, limit: int = 3
    ) -> list[ProvenTemplate]:
        ids = self._domain_index.get(domain, [])
        templates = [
            self._templates[tid] for tid in ids if tid in self._templates
        ]
        templates.sort(key=lambda t: t.avg_quality_score, reverse=True)
        return templates[:limit]

    def get_template_summaries(self, domain: str) -> list[dict]:
        return [
            {
                "goal_text": t.goal_text,
                "domain": t.domain,
                "winning_path": t.winning_path,
                "avg_quality_score": t.avg_quality_score,
                "times_used": t.times_used,
            }
            for t in self.find_templates(domain)
        ]

    def get_stats(self) -> dict[str, Any]:
        return {
            "proven_templates": len(self._templates),
            "candidates_validating": len(self._candidates),
            "domains_covered": len(self._domain_index),
        }

    def _make_key(self, domain: str, goal_text: str) -> str:
        return f"{domain}:{goal_text.lower().strip()[:100]}"
