from __future__ import annotations

import sys
from pathlib import Path

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

from account_registry import Account, AccountRef, AccountRegistryKind
from health_client import AccountSnapshot, HealthStatus
from tray_model import (
    TrayMenuItemKind,
    build_tray_model,
    format_account_label,
    format_limit_rows,
)


class _FakeRegistry:
    def __init__(
        self,
        accounts: list[Account],
        default_slug: str | None,
        kind: AccountRegistryKind = AccountRegistryKind.CODEX,
        locked_slugs: set[str] | None = None,
    ) -> None:
        self._accounts = list(accounts)
        self._default_slug = default_slug
        self.kind = kind
        self._locked_slugs = set(locked_slugs or ())

    def list(self) -> list[Account]:
        return list(self._accounts)

    def default_slug(self) -> str | None:
        return self._default_slug

    def is_locked(self, slug: str) -> bool:
        return slug in self._locked_slugs


def _account(
    slug: str,
    alias: str,
    plan: str | None = "plus",
    *,
    tool: str = "codex",
) -> Account:
    return Account(
        ref=AccountRef(tool, slug),
        alias=alias,
        account_home=Path("/tmp") / slug,
        email=f"{slug}@example.com",
        plan=plan,
        account_id=f"acct-{slug}",
    )


def _snapshot(
    used_primary: int | None,
    used_secondary: int | None,
    *,
    status=HealthStatus.OK,
    primary_reset_at: float | None = None,
    secondary_reset_at: float | None = None,
):
    return AccountSnapshot(
        status,
        used_primary,
        used_secondary,
        primary_reset_at=primary_reset_at,
        secondary_reset_at=secondary_reset_at,
    )


def test_build_tray_model_renders_single_provider_title_and_menu_state() -> None:
    registry = _FakeRegistry(
        accounts=[_account("rafa", "Rafa"), _account("roy", "Roy", "pro")],
        default_slug="roy",
    )
    snapshots = {
        "codex:rafa": _snapshot(12, 34),
        "codex:roy": AccountSnapshot(HealthStatus.BROKEN, None, None),
    }

    model = build_tray_model(registry, snapshots)

    assert model.title == "Codex: Roy (pro)"
    assert [item.kind for item in model.menu_items] == [
        TrayMenuItemKind.RADIO,
        TrayMenuItemKind.RADIO,
        TrayMenuItemKind.SEPARATOR,
        TrayMenuItemKind.ACTION,
        TrayMenuItemKind.SEPARATOR,
        TrayMenuItemKind.SUBMENU,
        TrayMenuItemKind.SEPARATOR,
        TrayMenuItemKind.ACTION,
    ]
    assert model.account_items[0].label == (
        "🔓 Rafa · plus\n"
        "5h [##################--] 88% left\n"
        "7d [#############-------] 66% left"
    )
    assert model.account_items[0].active is False
    assert model.account_items[1].label == "🔓 Roy · pro · ⚠ needs re-login"
    assert model.account_items[1].active is True
    assert model.menu_items[3].label == "Open dashboard"
    assert model.menu_items[3].action == "open_dashboard"
    assert model.menu_items[5].label == "Manage accounts"
    assert [child.kind for child in model.menu_items[5].children] == [
        TrayMenuItemKind.ACTION,
        TrayMenuItemKind.SEPARATOR,
        TrayMenuItemKind.ACTION,
        TrayMenuItemKind.ACTION,
        TrayMenuItemKind.ACTION,
        TrayMenuItemKind.ACTION,
        TrayMenuItemKind.ACTION,
        TrayMenuItemKind.ACTION,
        TrayMenuItemKind.ACTION,
        TrayMenuItemKind.ACTION,
    ]
    assert [child.label for child in model.menu_items[5].children if child.label] == [
        "Add account…",
        "Lock Rafa",
        "Refresh login for Rafa…",
        "Rename Rafa…",
        "Remove Rafa…",
        "Lock Roy",
        "Refresh login for Roy…",
        "Rename Roy…",
        "Remove Roy…",
    ]
    assert model.menu_items[7].label == "Quit"


def test_build_tray_model_renders_dual_provider_titles_and_submenus() -> None:
    codex_registry = _FakeRegistry(
        accounts=[_account("rafa", "Rafa"), _account("roy", "Roy", "pro")],
        default_slug="rafa",
    )
    claude_registry = _FakeRegistry(
        accounts=[
            _account("work", "Work", tool="claude"),
            _account("personal", "Personal", "max", tool="claude"),
        ],
        default_slug="personal",
        kind=AccountRegistryKind.CLAUDE,
    )
    snapshots = {
        "codex:rafa": _snapshot(10, 20),
        "codex:roy": _snapshot(80, 90),
        "claude:work": _snapshot(15, 25),
        "claude:personal": _snapshot(55, 65),
    }

    model = build_tray_model(codex_registry, snapshots, claude_registry)

    assert model.title == "Codex: Rafa (plus) · Claude: Personal (max)"
    assert [item.label for item in model.menu_items[:2]] == ["Codex", "Claude Code"]
    assert [child.kind for child in model.menu_items[0].children] == [
        TrayMenuItemKind.RADIO,
        TrayMenuItemKind.RADIO,
        TrayMenuItemKind.SEPARATOR,
        TrayMenuItemKind.SUBMENU,
    ]
    assert [child.label for child in model.menu_items[0].children if child.label] == [
        "🔓 Rafa · plus\n5h [##################--] 90% left\n7d [################----] 80% left",
        "🔓 Roy · pro\n5h [####----------------] 20% left\n7d [##------------------] 10% left",
        "Manage accounts",
    ]
    assert [child.label for child in model.menu_items[1].children] == [
        "🔓 Work · plus · work@example.com\n5h [#################---] 85% left\n7d [###############-----] 75% left",
        "🔓 Personal · max · personal@example.com\n5h [#########-----------] 45% left\n7d [#######-------------] 35% left",
    ]
    assert model.account_items[0].active is True
    assert model.account_items[3].active is True


def test_format_limit_rows_hides_expired_reset() -> None:
    snapshot = AccountSnapshot(
        HealthStatus.OK,
        10,
        20,
        primary_reset_at=1_700_000_000.0,
        secondary_reset_at=1_699_999_999.0,
    )

    assert format_limit_rows(snapshot, now=1_700_000_000.0) == (
        "5h [##################--] 90% left",
        "7d [################----] 80% left",
    )


def test_cached_limits_stay_visible_while_a_refresh_is_inconclusive() -> None:
    snapshot = AccountSnapshot(
        HealthStatus.UNKNOWN, 53, 82, checked_at=1_699_999_940.0
    )

    assert format_limit_rows(snapshot) == (
        "5h [#########-----------] 47% left",
        "7d [####----------------] 18% left",
    )
    assert format_account_label(
        _account("zync", "Zync", tool="claude"), snapshot, now=1_700_000_000.0
    ).splitlines() == [
        "Zync · plus · zync@example.com",
        "5h [#########-----------] 47% left",
        "7d [####----------------] 18% left",
    ]


def test_cached_limits_are_marked_with_their_age_once_stale() -> None:
    snapshot = AccountSnapshot(
        HealthStatus.UNKNOWN, 53, 82, checked_at=1_700_000_000.0 - 7 * 86400
    )

    assert format_account_label(
        _account("zync", "Zync", tool="claude"), snapshot, now=1_700_000_000.0
    ).splitlines()[0] == "Zync · plus · zync@example.com · 7d old"


def test_broken_account_hides_limit_rows() -> None:
    assert format_limit_rows(AccountSnapshot(HealthStatus.BROKEN, 53, 82)) is None


def test_locked_account_has_closed_icon_and_cannot_be_selected() -> None:
    registry = _FakeRegistry(
        accounts=[_account("owner", "Owner"), _account("agent", "Agent")],
        default_slug="owner",
        locked_slugs={"owner"},
    )

    model = build_tray_model(registry, {})

    assert model.title == "🔒 Codex: Owner (plus)"
    assert model.account_items[0].locked is True
    assert model.account_items[0].label == "🔒 Owner · plus"
    assert model.menu_items[0].sensitive is False
    manage = model.menu_items[5]
    assert manage.children[2].label == "Unlock Owner"
    assert manage.children[3].label == "Refresh login for Owner…"
    assert manage.children[3].sensitive is False
