from __future__ import annotations

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

StepStatus = Literal["pending", "running", "done", "skipped"]


@dataclass
class TaskStep:
    step_id: str
    label: str
    planes: frozenset[str]
    status: StepStatus = "pending"

    def to_dict(self) -> dict[str, Any]:
        return {
            "step_id": self.step_id,
            "label": self.label,
            "planes": sorted(self.planes),
            "status": self.status,
        }

    @classmethod
    def from_dict(cls, data: dict[str, Any]) -> TaskStep:
        planes_raw = data.get("planes") or []
        return cls(
            step_id=str(data.get("step_id") or uuid4().hex[:8]),
            label=str(data.get("label") or ""),
            planes=frozenset(str(p) for p in planes_raw),
            status=data.get("status") or "pending",  # type: ignore[arg-type]
        )


@dataclass
class TaskGraph:
    task_id: str
    goal: str
    steps: list[TaskStep] = field(default_factory=list)

    def progress(self) -> tuple[int, int]:
        total = len(self.steps)
        done = sum(1 for s in self.steps if s.status in ("done", "skipped"))
        return done, total

    def is_complete(self) -> bool:
        if not self.steps:
            return True
        return all(s.status in ("done", "skipped") for s in self.steps)

    def to_dict(self) -> dict[str, Any]:
        done, total = self.progress()
        return {
            "task_id": self.task_id,
            "goal": self.goal,
            "steps": [s.to_dict() for s in self.steps],
            "progress": {"done": done, "total": total},
        }

    @classmethod
    def from_dict(cls, data: dict[str, Any]) -> TaskGraph:
        steps = [TaskStep.from_dict(s) for s in (data.get("steps") or []) if isinstance(s, dict)]
        return cls(
            task_id=str(data.get("task_id") or uuid4().hex[:12]),
            goal=str(data.get("goal") or ""),
            steps=steps,
        )
