from __future__ import annotations

import json
import sys
from pathlib import Path
from types import SimpleNamespace

import pytest

sys.path.insert(0, str(Path(__file__).resolve().parents[1]))

import gateway_account_cli as cli
from account_registry import AuthorityBinding, AuthorityMode


class FakeAccount:
    tool = "codex"
    slug = "fixture"
    authority_binding = None


class FakeRegistry:
    def __init__(self, binding=None) -> None:
        self.binding = binding
        self.list_calls = 0

    def list(self):
        self.list_calls += 1
        return [FakeAccount()]

    def resolve_profile_token(self, token: str):
        return "fixture" if token in {"fixture", "Fixture"} else None

    def authority_binding_for(self, slug: str):
        if slug != "fixture":
            raise KeyError(slug)
        return self.binding


class FakeManager:
    def __init__(self, _registry) -> None:
        self.calls: list[str] = []
        self._current = FakeAccount()

    def stage(self, _account):
        self.calls.append("stage")
        return SimpleNamespace(as_dict=lambda: {"state": "dark"})

    def current(self, _slug: str):
        self.calls.append("current")
        return self._current

    def activate(self, _account):
        self.calls.append("activate")
        return SimpleNamespace(as_dict=lambda: {"state": "authority"})

    def cancel(self, _account):
        self.calls.append("cancel")
        return SimpleNamespace(as_dict=lambda: {"state": "native-cancelled"})


def test_wait_keeps_terminal_open_on_migration_error(
    monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str]
) -> None:
    class BrokenManager:
        def __init__(self, _registry) -> None:
            pass

        def stage(self, _account):
            raise cli.MigrationError("fixture login failed")

    prompts: list[str] = []
    monkeypatch.setattr(cli, "_registry", lambda _tool: FakeRegistry())
    monkeypatch.setattr(cli, "LocalGatewayAccountManager", BrokenManager)
    monkeypatch.setattr("builtins.input", lambda prompt: prompts.append(prompt) or "")

    assert (
        cli.main(["migrate", "--tool", "codex", "--account", "fixture", "--wait"])
        == 1
    )
    assert prompts == ["Press Enter to close…"]
    assert "fixture login failed" in capsys.readouterr().err

def test_migrate_stages_then_activates(monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str]) -> None:
    manager = FakeManager(FakeRegistry())
    monkeypatch.setattr(cli, "_registry", lambda _tool: FakeRegistry())
    monkeypatch.setattr(cli, "LocalGatewayAccountManager", lambda _registry: manager)

    assert cli.main(["migrate", "--tool", "codex", "--account", "fixture"]) == 0
    assert manager.calls == ["stage", "current", "activate"]
    assert json.loads(capsys.readouterr().out)["state"] == "authority"


@pytest.mark.parametrize(
    ("binding", "expected"),
    [
        (None, "native"),
        (
            AuthorityBinding(
                mode=AuthorityMode.SUBROUTER_DARK,
                authority_name="workstation",
                route_id="routefixture1234567890",
                provider="codex",
                proxy_grant_ref=Path("/tmp/fixture.grant"),
            ),
            "testing",
        ),
        (
            AuthorityBinding(
                mode=AuthorityMode.SUBROUTER,
                authority_name="workstation",
                route_id="routefixture1234567890",
                provider="codex",
                proxy_grant_ref=Path("/tmp/fixture.grant"),
            ),
            "active",
        ),
        (
            AuthorityBinding(
                mode=AuthorityMode.SUBROUTER,
                authority_name="workstation",
                route_id="routefixture1234567890",
                provider="codex",
                proxy_grant_ref=Path("/tmp/fixture.grant"),
                quiesced=True,
            ),
            "paused",
        ),
    ],
)
def test_status_is_metadata_only_and_never_lists_accounts(
    monkeypatch: pytest.MonkeyPatch,
    capsys: pytest.CaptureFixture[str],
    binding,
    expected: str,
) -> None:
    registry = FakeRegistry(binding)
    monkeypatch.setattr(cli, "_registry", lambda _tool: registry)

    assert cli.main(["status", "--tool", "codex", "--account", "Fixture"]) == 0
    assert registry.list_calls == 0
    assert json.loads(capsys.readouterr().out) == {
        "tool": "codex",
        "account": "fixture",
        "state": expected,
    }
