"""Plan Schema — GoalPlanner 的执行计划数据模型

定义 ExecutionPlan 和 PlanStep，用于 GoalPlanner 生成结构化执行计划。
"""

from __future__ import annotations

import uuid
from dataclasses import dataclass, field
from enum import Enum
from typing import Any


class PlanStepStatus(str, Enum):
    """计划步骤状态"""

    PENDING = "pending"
    RUNNING = "running"
    COMPLETED = "completed"
    FAILED = "failed"
    SKIPPED = "skipped"


class SkillGapLevel(str, Enum):
    """能力缺口严重程度"""

    NONE = "none"
    LOW = "low"
    MEDIUM = "medium"
    HIGH = "high"


@dataclass
class SkillGap:
    """能力缺口：某个步骤需要的 Skill 不可用"""

    step_name: str
    required_skill: str
    level: SkillGapLevel
    suggestion: str = ""


@dataclass
class PlanStep:
    """计划步骤

    每个步骤代表一个可执行的原子任务，包含名称、描述、依赖关系、
    并行分组和所需 Skill。
    """

    step_id: str
    name: str
    description: str
    dependencies: list[str] = field(default_factory=list)
    parallel_group: int = 0
    required_skills: list[str] = field(default_factory=list)
    input_data: dict[str, Any] = field(default_factory=dict)
    status: PlanStepStatus = PlanStepStatus.PENDING
    result: dict[str, Any] | None = None
    error: str | None = None

    def to_dict(self) -> dict[str, Any]:
        return {
            "step_id": self.step_id,
            "name": self.name,
            "description": self.description,
            "dependencies": self.dependencies,
            "parallel_group": self.parallel_group,
            "required_skills": self.required_skills,
            "input_data": self.input_data,
            "status": self.status.value if isinstance(self.status, PlanStepStatus) else self.status,
            "result": self.result,
            "error": self.error,
        }


@dataclass
class ExecutionPlan:
    """执行计划

    由 GoalPlanner 生成的结构化执行计划，包含多个 PlanStep，
    每个步骤有明确的依赖关系和并行分组。
    """

    plan_id: str = field(default_factory=lambda: str(uuid.uuid4())[:8])
    goal: str = ""
    steps: list[PlanStep] = field(default_factory=list)
    parallel_groups: list[list[str]] = field(default_factory=list)
    skill_gaps: list[SkillGap] = field(default_factory=list)
    confirmed: bool = False
    metadata: dict[str, Any] = field(default_factory=dict)

    @property
    def has_skill_gaps(self) -> bool:
        """是否存在能力缺口"""
        return any(gap.level in (SkillGapLevel.MEDIUM, SkillGapLevel.HIGH) for gap in self.skill_gaps)

    def get_step(self, step_id: str) -> PlanStep | None:
        """按 ID 获取步骤"""
        for step in self.steps:
            if step.step_id == step_id:
                return step
        return None

    def to_readable(self) -> str:
        """序列化为可读格式，用于人工确认"""
        lines = [f"📋 执行计划 [{self.plan_id}]", f"目标: {self.goal}", ""]

        for group_idx, group in enumerate(self.parallel_groups):
            lines.append(f"── 并行组 {group_idx + 1} ──")
            for step_id in group:
                step = self.get_step(step_id)
                if step is None:
                    continue
                deps = f" (依赖: {', '.join(step.dependencies)})" if step.dependencies else ""
                skills = f" [需要: {', '.join(step.required_skills)}]" if step.required_skills else ""
                lines.append(f"  [{step.step_id}] {step.name}{deps}{skills}")
                lines.append(f"      {step.description}")
            lines.append("")

        if self.skill_gaps:
            lines.append("⚠️ 能力缺口:")
            for gap in self.skill_gaps:
                lines.append(f"  - {gap.step_name}: 缺少 '{gap.required_skill}' ({gap.level.value})")
                if gap.suggestion:
                    lines.append(f"    建议: {gap.suggestion}")
            lines.append("")

        return "\n".join(lines)

    def to_dict(self) -> dict[str, Any]:
        return {
            "plan_id": self.plan_id,
            "goal": self.goal,
            "steps": [s.to_dict() for s in self.steps],
            "parallel_groups": self.parallel_groups,
            "skill_gaps": [
                {
                    "step_name": g.step_name,
                    "required_skill": g.required_skill,
                    "level": g.level.value,
                    "suggestion": g.suggestion,
                }
                for g in self.skill_gaps
            ],
            "confirmed": self.confirmed,
            "metadata": self.metadata,
        }
