"""Persist paused Avatar execution plan for resume/retry (0.2.2.24)."""

from __future__ import annotations

import json
import os
from dataclasses import dataclass
from datetime import datetime, timezone
from pathlib import Path
from typing import Any

DEFAULT_STATE_DIR = Path.home() / ".config" / "iuve-connect-agent"
PAUSED_PLAN_FILENAME = "avatar-paused-plan.json"
SCHEMA_VERSION = "0.2.2.24"


@dataclass(frozen=True)
class PausedPlanState:
    plan_id: str
    step_index: int
    pause_reason: str
    plan_json: dict[str, Any]
    updated_at: str = ""
    status: str = "paused"

    def to_dict(self) -> dict[str, Any]:
        return {
            "schema_version": SCHEMA_VERSION,
            "plan_id": self.plan_id,
            "step_index": self.step_index,
            "pause_reason": self.pause_reason,
            "plan_json": dict(self.plan_json),
            "updated_at": self.updated_at,
            "status": self.status,
        }

    @classmethod
    def from_dict(cls, raw: dict[str, Any]) -> PausedPlanState | None:
        plan_json = raw.get("plan_json")
        if not isinstance(plan_json, dict) or not plan_json.get("steps"):
            return None
        return cls(
            plan_id=str(raw.get("plan_id") or plan_json.get("plan_id") or ""),
            step_index=max(0, int(raw.get("step_index") or 0)),
            pause_reason=str(raw.get("pause_reason") or "unknown"),
            plan_json=dict(plan_json),
            updated_at=str(raw.get("updated_at") or ""),
            status=str(raw.get("status") or "paused"),
        )


def paused_step_index_for_plan(plan: dict[str, Any], failed_step_id: str) -> int:
    """Map failed step_id to 0-based index in plan.steps order."""
    steps = plan.get("steps") or []
    for index, step in enumerate(steps):
        if str(step.get("step_id") or "") == str(failed_step_id or ""):
            return index
    return max(0, len(steps) - 1)


class AvatarPausedPlanStore:
    def __init__(self, state_dir: Path | None = None) -> None:
        self._path = (state_dir or DEFAULT_STATE_DIR).expanduser() / PAUSED_PLAN_FILENAME

    @property
    def path(self) -> Path:
        return self._path

    def save_paused(
        self,
        *,
        plan: dict[str, Any],
        step_index: int,
        pause_reason: str,
    ) -> PausedPlanState:
        plan_id = str(plan.get("plan_id") or "").strip()
        if not plan_id:
            import secrets

            plan_id = f"plan_{secrets.token_hex(4)}"
            plan = dict(plan)
            plan["plan_id"] = plan_id
        state = PausedPlanState(
            plan_id=plan_id,
            step_index=max(0, int(step_index)),
            pause_reason=str(pause_reason or "unknown").strip(),
            plan_json=dict(plan),
            updated_at=datetime.now(timezone.utc).isoformat(),
            status="paused",
        )
        self._write(state.to_dict())
        return state

    def mark_completed(self, plan_id: str = "") -> None:
        current = self.load()
        if current is None:
            return
        if plan_id and current.plan_id != plan_id:
            return
        payload = current.to_dict()
        payload["status"] = "completed"
        payload["updated_at"] = datetime.now(timezone.utc).isoformat()
        self._write(payload)

    def clear(self) -> None:
        if self._path.exists():
            try:
                self._path.unlink()
            except OSError:
                pass

    def load(self) -> PausedPlanState | None:
        if not self._path.exists():
            return None
        try:
            raw = json.loads(self._path.read_text(encoding="utf-8"))
            if isinstance(raw, dict):
                return PausedPlanState.from_dict(raw)
        except Exception:
            pass
        return None

    def is_resumable(self) -> bool:
        state = self.load()
        return state is not None and state.status == "paused"

    def _write(self, payload: dict[str, Any]) -> None:
        self._path.parent.mkdir(parents=True, exist_ok=True)
        self._path.write_text(
            json.dumps(payload, ensure_ascii=True, indent=2, sort_keys=True),
            encoding="utf-8",
        )
        try:
            os.chmod(self._path, 0o600)
        except OSError:
            pass


_default_store: AvatarPausedPlanStore | None = None


def avatar_paused_plan_store() -> AvatarPausedPlanStore:
    global _default_store
    if _default_store is None:
        _default_store = AvatarPausedPlanStore()
    return _default_store
