"""Structured models for Beaver skill lifecycle."""

from __future__ import annotations

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


class SkillReviewState(str, Enum):
    DRAFT = "draft"
    IN_REVIEW = "in_review"
    APPROVED = "approved"
    REJECTED = "rejected"
    PUBLISHED = "published"
    DISABLED = "disabled"
    ARCHIVED = "archived"


class SkillStatus(str, Enum):
    ACTIVE = "active"
    DISABLED = "disabled"
    ARCHIVED = "archived"


@dataclass(slots=True)
class SkillSpec:
    name: str
    display_name: str
    description: str
    created_at: str
    updated_at: str
    current_version: str | None
    status: str = SkillStatus.ACTIVE.value
    tags: list[str] = field(default_factory=list)
    owners: list[str] = field(default_factory=list)
    source_kind: str = "workspace"
    lineage: list[str] = field(default_factory=list)

    def to_dict(self) -> dict[str, Any]:
        return {
            "name": self.name,
            "display_name": self.display_name,
            "description": self.description,
            "created_at": self.created_at,
            "updated_at": self.updated_at,
            "current_version": self.current_version,
            "status": self.status,
            "tags": list(self.tags),
            "owners": list(self.owners),
            "source_kind": self.source_kind,
            "lineage": list(self.lineage),
        }

    @classmethod
    def from_dict(cls, payload: dict[str, Any]) -> "SkillSpec":
        return cls(
            name=str(payload["name"]),
            display_name=str(payload.get("display_name") or payload["name"]),
            description=str(payload.get("description") or payload.get("display_name") or payload["name"]),
            created_at=str(payload.get("created_at") or ""),
            updated_at=str(payload.get("updated_at") or payload.get("created_at") or ""),
            current_version=_coerce_optional_str(payload.get("current_version")),
            status=str(payload.get("status") or SkillStatus.ACTIVE.value),
            tags=_coerce_string_list(payload.get("tags")),
            owners=_coerce_string_list(payload.get("owners")),
            source_kind=str(payload.get("source_kind") or "workspace"),
            lineage=_coerce_string_list(payload.get("lineage")),
        )


@dataclass(slots=True)
class SkillVersion:
    skill_name: str
    version: str
    content_hash: str
    summary_hash: str
    created_at: str
    created_by: str
    change_reason: str
    parent_version: str | None = None
    review_state: str = SkillReviewState.PUBLISHED.value
    frontmatter: dict[str, Any] = field(default_factory=dict)
    summary: str = ""
    tool_hints: list[str] = field(default_factory=list)
    provenance: dict[str, Any] = field(default_factory=dict)

    def to_dict(self) -> dict[str, Any]:
        return {
            "skill_name": self.skill_name,
            "version": self.version,
            "content_hash": self.content_hash,
            "summary_hash": self.summary_hash,
            "created_at": self.created_at,
            "created_by": self.created_by,
            "change_reason": self.change_reason,
            "parent_version": self.parent_version,
            "review_state": self.review_state,
            "frontmatter": dict(self.frontmatter),
            "summary": self.summary,
            "tool_hints": list(self.tool_hints),
            "provenance": dict(self.provenance),
        }

    @classmethod
    def from_dict(cls, payload: dict[str, Any]) -> "SkillVersion":
        return cls(
            skill_name=str(payload["skill_name"]),
            version=str(payload["version"]),
            content_hash=str(payload.get("content_hash") or ""),
            summary_hash=str(payload.get("summary_hash") or ""),
            created_at=str(payload.get("created_at") or ""),
            created_by=str(payload.get("created_by") or "unknown"),
            change_reason=str(payload.get("change_reason") or ""),
            parent_version=_coerce_optional_str(payload.get("parent_version")),
            review_state=str(payload.get("review_state") or SkillReviewState.PUBLISHED.value),
            frontmatter=dict(payload.get("frontmatter") or {}),
            summary=str(payload.get("summary") or ""),
            tool_hints=_coerce_string_list(payload.get("tool_hints")),
            provenance=dict(payload.get("provenance") or {}),
        )


@dataclass(slots=True)
class SkillDraft:
    draft_id: str
    skill_name: str
    base_version: str | None
    proposed_content: str
    proposed_frontmatter: dict[str, Any]
    created_at: str
    created_by: str
    trigger_run_id: str | None = None
    trigger_session_id: str | None = None
    reason: str = ""
    status: str = SkillReviewState.DRAFT.value
    evidence_refs: list[dict[str, Any]] = field(default_factory=list)
    proposal_kind: str = "revise_skill"

    def to_dict(self) -> dict[str, Any]:
        return {
            "draft_id": self.draft_id,
            "skill_name": self.skill_name,
            "base_version": self.base_version,
            "proposed_content": self.proposed_content,
            "proposed_frontmatter": dict(self.proposed_frontmatter),
            "created_at": self.created_at,
            "created_by": self.created_by,
            "trigger_run_id": self.trigger_run_id,
            "trigger_session_id": self.trigger_session_id,
            "reason": self.reason,
            "status": self.status,
            "evidence_refs": list(self.evidence_refs),
            "proposal_kind": self.proposal_kind,
        }

    @classmethod
    def from_dict(cls, payload: dict[str, Any]) -> "SkillDraft":
        return cls(
            draft_id=str(payload["draft_id"]),
            skill_name=str(payload["skill_name"]),
            base_version=_coerce_optional_str(payload.get("base_version")),
            proposed_content=str(payload.get("proposed_content") or ""),
            proposed_frontmatter=dict(payload.get("proposed_frontmatter") or {}),
            created_at=str(payload.get("created_at") or ""),
            created_by=str(payload.get("created_by") or "unknown"),
            trigger_run_id=_coerce_optional_str(payload.get("trigger_run_id")),
            trigger_session_id=_coerce_optional_str(payload.get("trigger_session_id")),
            reason=str(payload.get("reason") or ""),
            status=str(payload.get("status") or SkillReviewState.DRAFT.value),
            evidence_refs=list(payload.get("evidence_refs") or []),
            proposal_kind=str(payload.get("proposal_kind") or "revise_skill"),
        )


@dataclass(slots=True)
class SkillReviewRecord:
    review_id: str
    draft_id: str
    skill_name: str
    requested_at: str
    requested_by: str
    status: str
    reviewer: str | None = None
    reviewed_at: str | None = None
    notes: str = ""

    def to_dict(self) -> dict[str, Any]:
        return {
            "review_id": self.review_id,
            "draft_id": self.draft_id,
            "skill_name": self.skill_name,
            "requested_at": self.requested_at,
            "requested_by": self.requested_by,
            "status": self.status,
            "reviewer": self.reviewer,
            "reviewed_at": self.reviewed_at,
            "notes": self.notes,
        }

    @classmethod
    def from_dict(cls, payload: dict[str, Any]) -> "SkillReviewRecord":
        return cls(
            review_id=str(payload["review_id"]),
            draft_id=str(payload["draft_id"]),
            skill_name=str(payload["skill_name"]),
            requested_at=str(payload.get("requested_at") or ""),
            requested_by=str(payload.get("requested_by") or "unknown"),
            status=str(payload.get("status") or SkillReviewState.IN_REVIEW.value),
            reviewer=_coerce_optional_str(payload.get("reviewer")),
            reviewed_at=_coerce_optional_str(payload.get("reviewed_at")),
            notes=str(payload.get("notes") or ""),
        )


@dataclass(slots=True)
class SkillActivationReceipt:
    run_id: str
    session_id: str
    skill_name: str
    skill_version: str
    content_hash: str
    activated_at: str
    activation_reason: str
    tool_hints: list[str] = field(default_factory=list)

    def to_dict(self) -> dict[str, Any]:
        return {
            "run_id": self.run_id,
            "session_id": self.session_id,
            "skill_name": self.skill_name,
            "skill_version": self.skill_version,
            "content_hash": self.content_hash,
            "activated_at": self.activated_at,
            "activation_reason": self.activation_reason,
            "tool_hints": list(self.tool_hints),
        }

    @classmethod
    def from_dict(cls, payload: dict[str, Any]) -> "SkillActivationReceipt":
        return cls(
            run_id=str(payload["run_id"]),
            session_id=str(payload["session_id"]),
            skill_name=str(payload["skill_name"]),
            skill_version=str(payload["skill_version"]),
            content_hash=str(payload.get("content_hash") or ""),
            activated_at=str(payload.get("activated_at") or ""),
            activation_reason=str(payload.get("activation_reason") or ""),
            tool_hints=_coerce_string_list(payload.get("tool_hints")),
        )


def _coerce_optional_str(value: Any) -> str | None:
    if value in (None, ""):
        return None
    return str(value)


def _coerce_string_list(value: Any) -> list[str]:
    if not isinstance(value, list):
        return []
    result: list[str] = []
    for item in value:
        text = str(item).strip()
        if text:
            result.append(text)
    return result
