from __future__ import annotations

from enum import Enum
from typing import Any

from account_registry import Account, AccountRegistry, AuthorityMode
from authority_client import (
    LOCAL_AUTHORITY_NAME,
    ensure_local_authority_endpoint,
    gateway_health_snapshot,
)
from authority_migration import (
    AuthorityMigrationCoordinator,
    MigrationAcceptance,
    MigrationError,
    SubrouterMigrationAdmin,
)
from health_client import HealthStatus


class GatewayAccountState(str, Enum):
    NATIVE = "native"
    TESTING = "testing"
    ACTIVE = "active"
    PAUSED = "paused"


def gateway_account_state(account: Account) -> GatewayAccountState:
    binding = account.authority_binding
    if binding is None:
        return GatewayAccountState.NATIVE
    if binding.quiesced:
        return GatewayAccountState.PAUSED
    if binding.mode == AuthorityMode.SUBROUTER_DARK:
        return GatewayAccountState.TESTING
    if binding.mode == AuthorityMode.SUBROUTER:
        return GatewayAccountState.ACTIVE
    return GatewayAccountState.NATIVE


def gateway_state_label(account: Account) -> str:
    return {
        GatewayAccountState.NATIVE: "Native",
        GatewayAccountState.TESTING: "Gateway testing",
        GatewayAccountState.ACTIVE: "Gateway",
        GatewayAccountState.PAUSED: "Gateway paused",
    }[gateway_account_state(account)]


def _installed_local_acceptance(provider: str) -> MigrationAcceptance:
    """Release-level compatibility evidence for workstation-local custody.

    These are structural candidate gates. Per-account cutover additionally requires
    a fresh authority-owned login and a ready exact-route health response.
    """
    common = dict(
        cli=True,
        resume=True,
        streaming=True,
        quota_health=True,
        repair=True,
        restart=True,
        exact_route=True,
        no_provider_credentials=True,
    )
    if provider == "codex":
        return MigrationAcceptance(
            **common,
            responses=True,
            realtime=True,
            app_server=True,
        )
    if provider == "claude":
        return MigrationAcceptance(**common, http_sse=True)
    raise MigrationError("unsupported local Gateway provider")


class LocalGatewayAccountManager:
    """Systray-facing account custody manager for workstation-local Subrouter.

    Systray remains the sole account registry. Subrouter stores provider credentials
    only for accounts whose Systray record carries an authority binding.
    """

    def __init__(
        self,
        registry: AccountRegistry,
        *,
        admin: SubrouterMigrationAdmin | None = None,
        clock: Any | None = None,
    ) -> None:
        self.registry = registry
        self.admin = admin or SubrouterMigrationAdmin(registry)
        self.coordinator = AuthorityMigrationCoordinator(
            registry,
            self.admin,
            clock=clock,
        )

    def current(self, slug: str) -> Account:
        for account in self.registry.list():
            if account.slug == slug:
                return account
        raise KeyError(slug)

    def stage(self, account: Account):
        if gateway_account_state(self.current(account.slug)) is not GatewayAccountState.NATIVE:
            raise MigrationError("account is already Gateway-managed")
        ensure_local_authority_endpoint(self.registry.base_dir)
        return self.coordinator.stage_dark(
            self.current(account.slug), authority_name=LOCAL_AUTHORITY_NAME
        )

    def activate(self, account: Account):
        current = self.current(account.slug)
        if gateway_account_state(current) is not GatewayAccountState.TESTING:
            raise MigrationError("account is not in Gateway testing")
        ensure_local_authority_endpoint(self.registry.base_dir)
        health = gateway_health_snapshot(self.registry.base_dir, current)
        if health.status is not HealthStatus.OK:
            raise MigrationError(health.detail or "Gateway is not ready")
        return self.coordinator.promote(
            current, _installed_local_acceptance(current.tool)
        )

    def cancel(self, account: Account):
        return self.coordinator.cancel_dark(self.current(account.slug))

    def begin_rollback(self, account: Account) -> Account:
        return self.coordinator.begin_rollback(self.current(account.slug))

    def complete_rollback(self, account: Account, *, native_health: Any):
        return self.coordinator.complete_rollback(
            self.current(account.slug), native_health=native_health
        )
