"""State management — read/write per-service JSON files in ~/.konstant/."""

from __future__ import annotations

import json
from dataclasses import asdict, dataclass, field
from datetime import datetime, timezone
from pathlib import Path


STATE_DIR = Path.home() / ".konstant"


@dataclass
class ServiceState:
    status: str = "stopped"
    pid: int | None = None
    started_at: str | None = None
    restart_count: int = 0
    last_restart: str | None = None
    exit_code: int | None = None

    def is_running(self) -> bool:
        return self.status == "running"


class StateManager:
    def __init__(self, service_name: str) -> None:
        self.service_name = service_name
        self._dir = STATE_DIR
        self._dir.mkdir(parents=True, exist_ok=True)

    @property
    def path(self) -> Path:
        return self._dir / f"{self.service_name}.json"

    def read(self) -> ServiceState:
        if not self.path.exists():
            return ServiceState()
        try:
            raw = json.loads(self.path.read_text(encoding="utf-8"))
            return ServiceState(**{
                k: v for k, v in raw.items() if k in ServiceState.__dataclass_fields__
            })
        except (json.JSONDecodeError, TypeError):
            return ServiceState()

    def write(self, state: ServiceState) -> None:
        self.path.write_text(
            json.dumps(asdict(state), indent=2) + "\n",
            encoding="utf-8",
        )

    def update(self, **kwargs: object) -> ServiceState:
        state = self.read()
        for k, v in kwargs.items():
            if hasattr(state, k):
                setattr(state, k, v)
        self.write(state)
        return state

    def mark_running(self, pid: int) -> ServiceState:
        return self.update(
            status="running",
            pid=pid,
            started_at=_now_iso(),
            exit_code=None,
        )

    def mark_stopped(self, exit_code: int | None = None) -> ServiceState:
        return self.update(
            status="stopped",
            pid=None,
            exit_code=exit_code,
        )

    def mark_errored(self, exit_code: int | None = None) -> ServiceState:
        return self.update(
            status="errored",
            pid=None,
            exit_code=exit_code,
        )

    def record_restart(self) -> ServiceState:
        state = self.read()
        state.restart_count += 1
        state.last_restart = _now_iso()
        self.write(state)
        return state

    def reset_restart_count(self) -> ServiceState:
        return self.update(restart_count=0, last_restart=None)

    def delete(self) -> None:
        if self.path.exists():
            self.path.unlink()


def _now_iso() -> str:
    return datetime.now(timezone.utc).isoformat(timespec="seconds")
