from __future__ import annotations

import json
import sys
from pathlib import Path

import pytest

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

import command_router
from account_registry import AccountRegistry, AuthorityBinding, AuthorityMode
from authority_client import AuthorityLaunch, GatewayStatus
from health_client import AccountSnapshot, HealthStatus


def _runtime(home: Path) -> Path:
    return home / ".local/state/overdeck/systray/runtime"


def _prepare_account(home: Path) -> AccountRegistry:
    base = _runtime(home)
    registry = AccountRegistry(base_dir=base, legacy_codex_home=home / ".codex")
    account_home = registry.add_dir("fixture", "Fixture")
    account_home.joinpath("auth.json").write_text("{}", encoding="utf-8")
    registry.routing_rules_path.write_text(
        json.dumps(
            {
                "projects": {},
                "default": "fixture",
                "fallback_chain": [],
                "fallback_trigger": "broken_or_quota_exhausted",
                "quota_exhausted_threshold_pct": 100,
            }
        ),
        encoding="utf-8",
    )
    registry.health_cache_path.write_text(
        json.dumps(
            {
                "fixture": {
                    "status": "ok",
                    "primary_used_pct": 0,
                    "secondary_used_pct": 0,
                }
            }
        ),
        encoding="utf-8",
    )
    return registry


def test_dark_binding_builds_gateway_plan_but_executes_native_unchanged(
    tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
    home = tmp_path
    monkeypatch.setattr(command_router.Path, "home", lambda: home)
    monkeypatch.setattr(command_router.remote_dispatch, "in_container", lambda: True)
    registry = _prepare_account(home)
    adapter = command_router.CodexAdapter()
    monkeypatch.setattr(adapter, "sync_before_exec", lambda _base: [])
    captured: list[tuple[str, list[str], dict[str, str]]] = []
    monkeypatch.setattr(
        command_router.os,
        "execvpe",
        lambda executable, argv, env: captured.append((executable, argv, dict(env))),
    )

    native_router = command_router.CommandRouter(adapter, detect_project_name=lambda _cwd=None: "none")
    assert native_router.main(["cdx", "chat"]) == 0
    native = captured.pop()

    grant = tmp_path / "fixture.grant"
    grant.write_text("synthetic", encoding="utf-8")
    grant.chmod(0o600)
    registry.set_authority_binding(
        "fixture",
        AuthorityBinding(
            mode=AuthorityMode.SUBROUTER_DARK,
            authority_name="workstation",
            route_id="fixture-route",
            provider="codex",
            proxy_grant_ref=grant.resolve(),
        ),
    )
    prospective_home = tmp_path / "gateway"
    prospective = AuthorityLaunch(
        executable="codex",
        argv=("chat",),
        environment={"CODEX_HOME": str(prospective_home), "SUBROUTER_PROXY_KEY": "synthetic"},
        gateway_home=prospective_home,
        sanitized_status=GatewayStatus("ready", "Gateway: ready", 1.0),
    )
    calls: list[tuple[object, ...]] = []

    def fake_build(*args: object, **kwargs: object) -> AuthorityLaunch:
        calls.append((*args, kwargs))
        return prospective

    monkeypatch.setattr(command_router, "build_authority_launch", fake_build)
    dark_router = command_router.CommandRouter(adapter, detect_project_name=lambda _cwd=None: "none")

    assert dark_router.main(["cdx", "chat"]) == 0
    dark = captured.pop()

    assert calls
    assert dark_router._last_gateway_status == "Gateway: ready"
    assert dark == native
    assert dark[2]["CODEX_HOME"].endswith("accounts/fixture/CODEX_HOME")
    assert "SUBROUTER_PROXY_KEY" not in dark[2]


def test_dark_unexpected_gateway_failure_cannot_block_native_execution(
    tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
    home = tmp_path
    monkeypatch.setattr(command_router.Path, "home", lambda: home)
    monkeypatch.setattr(command_router.remote_dispatch, "in_container", lambda: True)
    registry = _prepare_account(home)
    registry.set_authority_binding(
        "fixture",
        AuthorityBinding(
            mode=AuthorityMode.SUBROUTER_DARK,
            authority_name="workstation",
            route_id="fixture-route",
            provider="codex",
            proxy_grant_ref=(tmp_path / "missing.grant").resolve(),
        ),
    )
    monkeypatch.setattr(
        command_router,
        "build_authority_launch",
        lambda *_args, **_kwargs: (_ for _ in ()).throw(PermissionError("private path")),
    )
    captured: list[list[str]] = []
    monkeypatch.setattr(
        command_router.os,
        "execvpe",
        lambda _executable, argv, _env: captured.append(argv),
    )
    router = command_router.CommandRouter(
        command_router.CodexAdapter(), detect_project_name=lambda _cwd=None: "none"
    )

    assert router.main(["cdx", "chat"]) == 0
    assert captured == [[router.adapter.exec_name, "chat"]]
    assert router._last_gateway_status == "Gateway: unavailable"


def test_info_only_does_not_resolve_authority_binding(
    tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
    home = tmp_path
    monkeypatch.setattr(command_router.Path, "home", lambda: home)
    adapter = command_router.CodexAdapter()
    monkeypatch.setattr(
        adapter,
        "account",
        lambda *_args, **_kwargs: pytest.fail("info-only resolved authority metadata"),
    )
    monkeypatch.setattr(adapter, "sync_before_exec", lambda _base: [])
    monkeypatch.setenv("OPENAI_API_KEY", "must-not-survive")
    monkeypatch.setenv("SUBROUTER_PROXY_KEY", "must-not-survive")
    captured: list[tuple[str, list[str], dict[str, str]]] = []
    monkeypatch.setattr(
        command_router.os,
        "execvpe",
        lambda executable, argv, env: captured.append((executable, argv, dict(env))),
    )

    router = command_router.CommandRouter(adapter, detect_project_name=lambda _cwd=None: "none")

    assert router.main(["cdx", "--version"]) == 0
    assert captured and captured[0][1] == [adapter.exec_name, "--version"]
    environment = captured[0][2]
    assert "OPENAI_API_KEY" not in environment
    assert "SUBROUTER_PROXY_KEY" not in environment
    assert environment["CODEX_HOME"].endswith("credentialless-info-homes/codex")
    assert "accounts/fixture" not in environment["CODEX_HOME"]


def test_active_gateway_status_never_reads_native_account_health(
    tmp_path: Path,
    monkeypatch: pytest.MonkeyPatch,
    capsys: pytest.CaptureFixture[str],
) -> None:
    home = tmp_path
    monkeypatch.setattr(command_router.Path, "home", lambda: home)
    registry = _prepare_account(home)
    grant = tmp_path / "fixture.grant"
    grant.write_text("synthetic", encoding="utf-8")
    grant.chmod(0o600)
    registry.set_authority_binding(
        "fixture",
        AuthorityBinding(
            mode=AuthorityMode.SUBROUTER,
            authority_name="workstation",
            route_id="fixture-route",
            provider="codex",
            proxy_grant_ref=grant.resolve(),
        ),
    )
    monkeypatch.setattr(
        command_router,
        "build_authority_launch",
        lambda *_args, **_kwargs: pytest.fail("status built an executable launch plan"),
    )
    monkeypatch.setattr(
        command_router,
        "gateway_health_snapshot",
        lambda *_args, **_kwargs: AccountSnapshot(
            HealthStatus.OK,
            None,
            None,
            checked_at=2.0,
            detail="Gateway: ready",
        ),
    )
    monkeypatch.setattr(
        command_router.AccountHealthClient,
        "fetch",
        lambda *_args, **_kwargs: pytest.fail("active status opened native account health"),
    )
    router = command_router.CommandRouter(
        command_router.CodexAdapter(), detect_project_name=lambda _cwd=None: "none"
    )

    assert router.main(["cdx", "--status", "--json"]) == 0

    payload = json.loads(capsys.readouterr().out)
    assert payload["status"] == "ok"
    assert payload["detail"] == "Gateway: ready"


def test_gateway_mode_fails_closed_instead_of_native_fallback(
    tmp_path: Path, monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str]
) -> None:
    home = tmp_path
    monkeypatch.setattr(command_router.Path, "home", lambda: home)
    registry = _prepare_account(home)
    grant = tmp_path / "missing.grant"
    registry.set_authority_binding(
        "fixture",
        AuthorityBinding(
            mode=AuthorityMode.SUBROUTER,
            authority_name="missing",
            route_id="fixture-route",
            provider="codex",
            proxy_grant_ref=grant.resolve(),
        ),
    )
    executed = False

    def fake_exec(*_args: object) -> None:
        nonlocal executed
        executed = True

    monkeypatch.setattr(command_router.os, "execvpe", fake_exec)
    router = command_router.CommandRouter(
        command_router.CodexAdapter(), detect_project_name=lambda _cwd=None: "none"
    )

    assert router.main(["cdx", "chat"]) == 1

    assert executed is False
    assert capsys.readouterr().err.strip().endswith("cdx: Gateway: migration required")


def test_quiesced_binding_blocks_both_gateway_and_native_launches(
    tmp_path: Path,
    monkeypatch: pytest.MonkeyPatch,
    capsys: pytest.CaptureFixture[str],
) -> None:
    home = tmp_path
    monkeypatch.setattr(command_router.Path, "home", lambda: home)
    monkeypatch.setattr(command_router.remote_dispatch, "in_container", lambda: True)
    registry = _prepare_account(home)
    grant = tmp_path / "fixture.grant"
    grant.write_text("synthetic", encoding="utf-8")
    grant.chmod(0o600)
    registry.set_authority_binding(
        "fixture",
        AuthorityBinding(
            mode=AuthorityMode.SUBROUTER,
            authority_name="workstation",
            route_id="fixture-route",
            provider="codex",
            proxy_grant_ref=grant.resolve(),
            quiesced=True,
        ),
    )
    monkeypatch.setattr(
        command_router,
        "build_authority_launch",
        lambda *_args, **_kwargs: pytest.fail("quiesced launch resolved gateway material"),
    )
    monkeypatch.setattr(
        command_router.os,
        "execvpe",
        lambda *_args, **_kwargs: pytest.fail("quiesced launch executed native provider"),
    )
    adapter = command_router.CodexAdapter()
    monkeypatch.setattr(
        adapter,
        "sync_before_exec",
        lambda *_args, **_kwargs: pytest.fail("quiesced launch synchronized native state"),
    )
    router = command_router.CommandRouter(adapter, detect_project_name=lambda _cwd=None: "none")

    assert router.main(["cdx", "chat"]) == 1
    assert router._last_gateway_status == "Gateway: migration paused"
    assert capsys.readouterr().err.strip().endswith("cdx: Gateway: migration paused")


def test_gateway_captured_run_is_forced_local_even_when_remote_offload_is_enabled(
    tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
    router = command_router.CommandRouter(
        command_router.CodexAdapter(), detect_project_name=lambda _cwd=None: "none"
    )
    log_path = tmp_path / "capture.log"
    opened: list[bool] = []
    supervised: list[list[str]] = []
    monkeypatch.setattr(command_router.remote_dispatch, "should_offload", lambda: True)
    monkeypatch.setattr(
        command_router.remote_dispatch,
        "open_session",
        lambda *_args, **_kwargs: opened.append(True),
    )
    monkeypatch.setattr(
        command_router,
        "supervise",
        lambda argv, _env, _log, key=None: supervised.append(list(argv)) or 0,
    )

    assert router._run_captured(
        ["exec", "hello"],
        {"SUBROUTER_PROXY_KEY": "synthetic"},
        log_path,
        None,
        1.0,
        allow_offload=False,
    ) == 0

    assert opened == []
    assert supervised == [["codex", "exec", "hello"]]


def test_gateway_interactive_run_executes_locally_without_remote_containment(
    tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
    home = tmp_path
    monkeypatch.setattr(command_router.Path, "home", lambda: home)
    registry = _prepare_account(home)
    grant = tmp_path / "fixture.grant"
    grant.write_text("synthetic", encoding="utf-8")
    grant.chmod(0o600)
    registry.set_authority_binding(
        "fixture",
        AuthorityBinding(
            mode=AuthorityMode.SUBROUTER,
            authority_name="workstation",
            route_id="fixture-route",
            provider="codex",
            proxy_grant_ref=grant.resolve(),
        ),
    )
    gateway_home = tmp_path / "gateway"
    monkeypatch.setattr(
        command_router,
        "build_authority_launch",
        lambda *_args, **_kwargs: AuthorityLaunch(
            executable="codex",
            argv=("chat",),
            environment={
                "HOME": str(gateway_home),
                "CODEX_HOME": str(gateway_home),
                "SUBROUTER_PROXY_KEY": "synthetic",
            },
            gateway_home=gateway_home,
            sanitized_status=GatewayStatus("ready", "Gateway: ready", 1.0),
        ),
    )
    monkeypatch.setattr(command_router.remote_dispatch, "should_offload", lambda: True)
    monkeypatch.setattr(
        command_router.remote_dispatch,
        "open_session",
        lambda *_args, **_kwargs: pytest.fail("Gateway interactive launch offloaded remotely"),
    )
    executed: list[tuple[str, list[str], dict[str, str]]] = []
    monkeypatch.setattr(
        command_router.os,
        "execvpe",
        lambda executable, argv, env: executed.append((executable, list(argv), dict(env))),
    )
    adapter = command_router.CodexAdapter()
    monkeypatch.setattr(adapter, "capture_log_path", lambda _argv: None)
    router = command_router.CommandRouter(adapter, detect_project_name=lambda _cwd=None: "none")

    assert router.main(["cdx", "chat"]) == 0
    assert executed and executed[0][0:2] == ("codex", ["codex", "chat"])
    assert executed[0][2]["SUBROUTER_PROXY_KEY"] == "synthetic"
