"""Thinking layer data models."""

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

ConstraintType = Literal["physics", "habit"]


@dataclass
class BenchmarkElement:
    """A single element of the benchmark map."""

    name: str = ""
    description: str = ""
    tool: str = ""
    category: str = ""  # approach, tool, pattern, assumption, sequence
    is_standard: bool = True
    rationale: str = ""

    def to_dict(self) -> dict[str, Any]:
        return {
            "name": self.name,
            "description": self.description,
            "tool": self.tool,
            "category": self.category,
            "is_standard": self.is_standard,
            "rationale": self.rationale,
        }

    @classmethod
    def from_dict(cls, data: dict[str, Any]) -> "BenchmarkElement":
        return cls(
            name=data.get("name", ""),
            description=data.get("description", ""),
            tool=data.get("tool", ""),
            category=data.get("category", "approach"),
            is_standard=data.get("is_standard", True),
            rationale=data.get("rationale", ""),
        )


@dataclass
class Constraint:
    """A classified constraint from the Physicist."""

    element_name: str = ""
    constraint_type: ConstraintType = "habit"
    reasoning: str = ""
    breakable: bool = True
    alternatives: list[str] = field(default_factory=list)

    def to_dict(self) -> dict[str, Any]:
        return {
            "element_name": self.element_name,
            "constraint_type": self.constraint_type,
            "reasoning": self.reasoning,
            "breakable": self.breakable,
            "alternatives": self.alternatives,
        }

    @classmethod
    def from_dict(cls, data: dict[str, Any]) -> "Constraint":
        return cls(
            element_name=data.get("element_name", ""),
            constraint_type=data.get("constraint_type", "habit"),
            reasoning=data.get("reasoning", ""),
            breakable=data.get("breakable", True),
            alternatives=data.get("alternatives", []),
        )


@dataclass
class BenchmarkMap:
    """The Scout's output — structured map of the standard approach."""

    goal_text: str = ""
    domain: str = ""
    elements: list[BenchmarkElement] = field(default_factory=list)
    standard_tools: list[str] = field(default_factory=list)
    standard_sequence: list[str] = field(default_factory=list)
    assumptions: list[str] = field(default_factory=list)
    cross_domain_components: list[str] = field(default_factory=list)
    created_at: datetime = field(default_factory=datetime.utcnow)

    def to_dict(self) -> dict[str, Any]:
        return {
            "goal_text": self.goal_text,
            "domain": self.domain,
            "elements": [e.to_dict() for e in self.elements],
            "standard_tools": self.standard_tools,
            "standard_sequence": self.standard_sequence,
            "assumptions": self.assumptions,
            "cross_domain_components": self.cross_domain_components,
            "created_at": self.created_at.isoformat(),
        }

    @classmethod
    def from_dict(cls, data: dict[str, Any]) -> "BenchmarkMap":
        return cls(
            goal_text=data.get("goal_text", ""),
            domain=data.get("domain", ""),
            elements=[BenchmarkElement.from_dict(e) for e in data.get("elements", [])],
            standard_tools=data.get("standard_tools", []),
            standard_sequence=data.get("standard_sequence", []),
            assumptions=data.get("assumptions", []),
            cross_domain_components=data.get("cross_domain_components", []),
        )


@dataclass
class ClassifiedMap:
    """The Physicist's output — benchmark with constraints classified."""

    benchmark: BenchmarkMap = field(default_factory=BenchmarkMap)
    constraints: list[Constraint] = field(default_factory=list)
    physics_count: int = 0
    habit_count: int = 0
    created_at: datetime = field(default_factory=datetime.utcnow)

    def __post_init__(self):
        if self.constraints and not self.physics_count:
            self.physics_count = sum(
                1 for c in self.constraints if c.constraint_type == "physics"
            )
            self.habit_count = sum(
                1 for c in self.constraints if c.constraint_type == "habit"
            )

    def get_habits(self) -> list[Constraint]:
        return [c for c in self.constraints if c.constraint_type == "habit"]

    def get_physics(self) -> list[Constraint]:
        return [c for c in self.constraints if c.constraint_type == "physics"]

    def to_dict(self) -> dict[str, Any]:
        return {
            "benchmark": self.benchmark.to_dict(),
            "constraints": [c.to_dict() for c in self.constraints],
            "physics_count": self.physics_count,
            "habit_count": self.habit_count,
        }

    @classmethod
    def from_dict(cls, data: dict[str, Any]) -> "ClassifiedMap":
        return cls(
            benchmark=BenchmarkMap.from_dict(data.get("benchmark", {})),
            constraints=[Constraint.from_dict(c) for c in data.get("constraints", [])],
        )


@dataclass
class Path:
    """A single execution path generated by the Architect."""

    id: str = ""  # "A", "B", or "C"
    label: str = ""
    description: str = ""
    divergence_level: float = 0.0
    habits_broken: list[str] = field(default_factory=list)
    physics_respected: list[str] = field(default_factory=list)
    cross_domain_imports: list[str] = field(default_factory=list)
    steps: list[dict[str, Any]] = field(default_factory=list)
    tools_required: list[str] = field(default_factory=list)
    estimated_duration_ms: int = 0
    risk_level: str = "medium"
    confidence: float = 0.5

    def to_dict(self) -> dict[str, Any]:
        return {
            "id": self.id,
            "label": self.label,
            "description": self.description,
            "divergence_level": self.divergence_level,
            "habits_broken": self.habits_broken,
            "physics_respected": self.physics_respected,
            "cross_domain_imports": self.cross_domain_imports,
            "steps": self.steps,
            "tools_required": self.tools_required,
            "estimated_duration_ms": self.estimated_duration_ms,
            "risk_level": self.risk_level,
            "confidence": self.confidence,
        }

    @classmethod
    def from_dict(cls, data: dict[str, Any]) -> "Path":
        return cls(
            id=data.get("id", ""),
            label=data.get("label", ""),
            description=data.get("description", ""),
            divergence_level=data.get("divergence_level", 0.0),
            habits_broken=data.get("habits_broken", []),
            physics_respected=data.get("physics_respected", []),
            cross_domain_imports=data.get("cross_domain_imports", []),
            steps=data.get("steps", []),
            tools_required=data.get("tools_required", []),
            estimated_duration_ms=data.get("estimated_duration_ms", 0),
            risk_level=data.get("risk_level", "medium"),
            confidence=data.get("confidence", 0.5),
        )


@dataclass
class ThinkingResult:
    """Complete output of the thinking layer."""

    id: UUID = field(default_factory=uuid4)
    goal_text: str = ""
    benchmark_map: BenchmarkMap = field(default_factory=BenchmarkMap)
    classified_map: ClassifiedMap = field(default_factory=ClassifiedMap)
    paths: list[Path] = field(default_factory=list)
    recommended_path: str = "A"
    thinking_duration_ms: int = 0
    created_at: datetime = field(default_factory=datetime.utcnow)

    def get_path(self, path_id: str) -> Path | None:
        for p in self.paths:
            if p.id == path_id:
                return p
        return None

    def to_dict(self) -> dict[str, Any]:
        return {
            "id": str(self.id),
            "goal_text": self.goal_text,
            "benchmark_map": self.benchmark_map.to_dict(),
            "classified_map": self.classified_map.to_dict(),
            "paths": [p.to_dict() for p in self.paths],
            "recommended_path": self.recommended_path,
            "thinking_duration_ms": self.thinking_duration_ms,
        }

    @classmethod
    def from_dict(cls, data: dict[str, Any]) -> "ThinkingResult":
        return cls(
            id=UUID(data["id"]) if data.get("id") else uuid4(),
            goal_text=data.get("goal_text", ""),
            benchmark_map=BenchmarkMap.from_dict(data.get("benchmark_map", {})),
            classified_map=ClassifiedMap.from_dict(data.get("classified_map", {})),
            paths=[Path.from_dict(p) for p in data.get("paths", [])],
            recommended_path=data.get("recommended_path", "A"),
            thinking_duration_ms=data.get("thinking_duration_ms", 0),
        )
