from __future__ import annotations

import json
import subprocess
import sys
from pathlib import Path

import pytest

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

from account_registry import Account, AccountRef
from claude_credentials import pin_account_uuid
from claude_health_client import ClaudeHealthClient
from claude_identity import TokenIdentity
from claude_oauth import UsageReading
from health_client import HealthStatus

_LIVE_CREDENTIALS = {"claudeAiOauth": {"accessToken": "live", "refreshToken": "live-refresh"}}


def _account(home: Path) -> Account:
    return Account(
        AccountRef("claude", "avi"),
        "Avi",
        home,
        "avi@example.com",
        "max",
        "acct_123",
    )


def _homes(tmp_path: Path, *, empty_account_credentials: bool) -> tuple[Path, Path]:
    account_home = tmp_path / "CLAUDE_HOME"
    account_home.mkdir()
    live_home = tmp_path / "live"
    live_home.mkdir()
    pin_account_uuid(account_home, "shared-uuid")
    if empty_account_credentials:
        (account_home / ".credentials.json").write_text(
            json.dumps({"claudeAiOauth": {"accessToken": "", "refreshToken": ""}}),
            encoding="utf-8",
        )
    (live_home / ".credentials.json").write_text(
        json.dumps(_LIVE_CREDENTIALS), encoding="utf-8"
    )
    return account_home, live_home


class _LiveTokenIdentity:
    def __init__(self, timeout_secs: float = 10.0) -> None:
        pass

    def account_uuid_for(self, _credentials_path: Path) -> str:
        return "shared-uuid"

    def identify_token(self, _access_token: str) -> TokenIdentity:
        return TokenIdentity("shared-uuid", None)


def test_fetch_reads_the_live_home_when_the_account_copy_has_no_tokens(
    monkeypatch: pytest.MonkeyPatch,
    tmp_path: Path,
) -> None:
    account_home, live_home = _homes(tmp_path, empty_account_credentials=True)
    sessions: list[Path] = []

    class LiveSession:
        def __init__(
            self,
            credentials_path: Path,
            timeout_secs: float = 5.0,
            allow_rotation: bool = False,
            rotation_backup_path=None,
        ) -> None:
            sessions.append(credentials_path)

        def get_usage_reading(self) -> UsageReading:
            return UsageReading(payload=self.get_usage(), access_token="fake-token")

        def get_usage(self) -> dict[str, object]:
            return {
                "five_hour": {"utilization": 10, "resets_at": 1_700_003_600.0},
                "seven_day": {"utilization": 42, "resets_at": 1_700_600_000.0},
            }

    monkeypatch.setattr("claude_credentials.LIVE_CLAUDE_HOME", live_home)
    monkeypatch.setattr("claude_health_client.ClaudeTokenIdentity", _LiveTokenIdentity)
    monkeypatch.setattr(
        ClaudeHealthClient,
        "_auth_status",
        staticmethod(lambda _path, _creds, _timeout: HealthStatus.OK),
    )
    monkeypatch.setattr("claude_health_client.ClaudeOAuthSession", LiveSession)
    monkeypatch.setattr("claude_health_client.time.time", lambda: 1_700_000_000.0)

    snapshot = ClaudeHealthClient().fetch(_account(account_home))

    assert sessions == [live_home / ".credentials.json"]
    assert snapshot.status == HealthStatus.OK
    assert snapshot.primary_used_pct == 10
    assert snapshot.secondary_used_pct == 42
    assert snapshot.primary_reset_at == 1_700_003_600.0
    assert snapshot.secondary_reset_at == 1_700_600_000.0
    assert (
        json.loads((live_home / ".credentials.json").read_text(encoding="utf-8"))
        == _LIVE_CREDENTIALS
    )


def test_auth_status_probes_the_resolved_credentials(
    monkeypatch: pytest.MonkeyPatch,
    tmp_path: Path,
) -> None:
    account_home, live_home = _homes(tmp_path, empty_account_credentials=False)
    probed: list[dict[str, object]] = []

    def fake_run(*_: object, **kwargs: object) -> subprocess.CompletedProcess[str]:
        env = kwargs["env"]
        assert isinstance(env, dict)
        config_dir = Path(str(env["CLAUDE_CONFIG_DIR"]))
        probed.append(json.loads((config_dir / ".credentials.json").read_text(encoding="utf-8")))
        return subprocess.CompletedProcess(
            args=["claude", "auth", "status", "--json"],
            returncode=0,
            stdout='{"loggedIn": true}\n',
            stderr="",
        )

    class LiveSession:
        def __init__(
            self,
            credentials_path: Path,
            timeout_secs: float = 5.0,
            allow_rotation: bool = False,
            rotation_backup_path=None,
        ) -> None:
            self.credentials_path = credentials_path

        def get_usage_reading(self) -> UsageReading:
            return UsageReading(payload=self.get_usage(), access_token="fake-token")

        def get_usage(self) -> dict[str, object]:
            return {"five_hour": {"utilization": 10}}

    monkeypatch.setattr("claude_credentials.LIVE_CLAUDE_HOME", live_home)
    monkeypatch.setattr("claude_health_client.ClaudeTokenIdentity", _LiveTokenIdentity)
    monkeypatch.setattr("claude_health_client.subprocess.run", fake_run)
    monkeypatch.setattr("claude_health_client.ClaudeOAuthSession", LiveSession)
    monkeypatch.setattr("claude_health_client.time.time", lambda: 1_700_000_000.0)

    ClaudeHealthClient().fetch(_account(account_home))

    assert probed == [_LIVE_CREDENTIALS]
