"""Lease pane titles from stored execution labels."""
from __future__ import annotations

import json
import secrets
from dataclasses import dataclass
from pathlib import Path
from typing import Protocol


class PaneTitleError(ValueError):
    """Raised when a title lease cannot be acquired or released."""


class PaneTitleBackend(Protocol):
    def get_title(self, pane_id: str) -> str: ...
    def set_title(self, pane_id: str, title: str) -> None: ...
    def available(self) -> bool: ...


@dataclass
class MemoryPaneBackend:
    titles: dict[str, str]
    capable: bool = True

    def get_title(self, pane_id: str) -> str:
        return self.titles.get(pane_id, "")

    def set_title(self, pane_id: str, title: str) -> None:
        self.titles[pane_id] = title

    def available(self) -> bool:
        return self.capable


@dataclass(frozen=True)
class PaneTitleLease:
    run_ref: str
    participant_ref: str
    role_execution_ref: str
    invocation_ref: str | None
    pane_backend: str
    pane_id: str
    previous_title: str
    applied_title: str
    owner_token: str
    status: str


class UnavailablePaneBackend:
    def get_title(self, pane_id: str) -> str:
        return ""

    def set_title(self, pane_id: str, title: str) -> None:
        return None

    def available(self) -> bool:
        return False


def acquire_pane_title(
    *,
    backend: PaneTitleBackend,
    pane_id: str,
    execution_label: str,
    run_ref: str,
    participant_ref: str,
    role_execution_ref: str,
    invocation_ref: str | None = None,
    pane_backend: str = "cmux",
) -> PaneTitleLease:
    if not backend.available():
        return PaneTitleLease(
            run_ref=run_ref,
            participant_ref=participant_ref,
            role_execution_ref=role_execution_ref,
            invocation_ref=invocation_ref,
            pane_backend=pane_backend,
            pane_id=pane_id,
            previous_title="",
            applied_title=execution_label,
            owner_token="",
            status="not-applicable",
        )
    previous = backend.get_title(pane_id)
    backend.set_title(pane_id, execution_label)
    return PaneTitleLease(
        run_ref=run_ref,
        participant_ref=participant_ref,
        role_execution_ref=role_execution_ref,
        invocation_ref=invocation_ref,
        pane_backend=pane_backend,
        pane_id=pane_id,
        previous_title=previous,
        applied_title=execution_label,
        owner_token=secrets.token_hex(8),
        status="acquired",
    )


def release_pane_title(
    lease: PaneTitleLease,
    backend: PaneTitleBackend,
    *,
    owner_token: str,
) -> PaneTitleLease:
    if lease.status == "not-applicable":
        return lease
    if owner_token != lease.owner_token:
        raise PaneTitleError("owner token does not match")
    current = backend.get_title(lease.pane_id)
    if current != lease.applied_title:
        return PaneTitleLease(**{**lease.__dict__, "status": "manual-change-preserved"})
    backend.set_title(lease.pane_id, lease.previous_title)
    return PaneTitleLease(**{**lease.__dict__, "status": "released"})


def cleanup_pane_title(
    lease: PaneTitleLease, backend: PaneTitleBackend
) -> PaneTitleLease:
    if lease.status == "not-applicable":
        return lease
    backend.set_title(lease.pane_id, lease.previous_title)
    return PaneTitleLease(**{**lease.__dict__, "status": "cleaned"})


def main(argv: list[str] | None = None) -> int:
    import argparse

    parser = argparse.ArgumentParser(prog="okstra pane-title")
    parser.add_argument("action", choices=("acquire", "release", "cleanup"))
    parser.add_argument("--execution-label", default="")
    parser.add_argument("--pane-id", default="")
    parser.add_argument("--json", action="store_true")
    args = parser.parse_args(argv)
    backend = UnavailablePaneBackend()
    lease = acquire_pane_title(
        backend=backend,
        pane_id=args.pane_id or "none",
        execution_label=args.execution_label or "unused",
        run_ref="run",
        participant_ref="participant",
        role_execution_ref="role",
    )
    payload = {"status": lease.status, "appliedTitle": lease.applied_title}
    print(json.dumps(payload, ensure_ascii=False))
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
