from __future__ import annotations

import sys
from pathlib import Path
from typing import Any

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

from tests.cards_helpers import make_account_vm, make_bar, make_callbacks
from ui.account_card import AccountCard, _FallbackGtk


class _NoShowBox(_FallbackGtk.Box):
    def __init__(self, orientation=None, spacing: int = 0) -> None:
        super().__init__(orientation=orientation, spacing=spacing)
        self.no_show_all = False
        self.show_all_states: list[bool] = []

    def set_no_show_all(self, no_show_all: bool) -> None:
        self.no_show_all = bool(no_show_all)

    def show_all(self) -> None:
        self.show_all_states.append(self.no_show_all)


class _NoShowGtk(_FallbackGtk):
    Box = _NoShowBox


def _card(vm: Any, calls: list[tuple[Any, ...]] | None = None) -> AccountCard:
    return AccountCard(vm, make_callbacks(calls if calls is not None else []), gtk_module=_FallbackGtk)


def test_renders_badges_bars_and_texts_from_vm() -> None:
    vm = make_account_vm(alias="Work", plan_text="max", is_default=True)
    card = _card(vm)

    assert "account-card" in card.widget.css_classes
    assert "attention" not in card.widget.css_classes
    assert card.alias_label.text == "Work"
    assert card.plan_label.text == "max"
    assert card.checked_label.text == "⟳ 12s ago"
    assert card.default_badge.visible is True
    assert card.default_badge.text == "DEFAULT"
    assert "default-badge" in card.default_badge.css_classes
    assert card.health_badge.visible is False
    assert "health-badge" in card.health_badge.css_classes
    assert "ok" in card.health_badge.css_classes
    assert card.primary_window_label.text == "5h"
    assert card.primary_bar.fraction == 0.42
    assert card.primary_value_label.text == "58% left"
    assert card.primary_reset_label.text == "↺ 2h10m"
    assert "quota-bar" in card.primary_bar.css_classes
    assert card.secondary_window_label.text == "7d"
    assert card.secondary_value_label.text == "33% left"


def test_quota_rows_allow_show_all_before_restoring_suppression() -> None:
    card = AccountCard(make_account_vm(), make_callbacks([]), gtk_module=_NoShowGtk)

    assert card.primary_row.show_all_states == [False]
    assert card.secondary_row.show_all_states == [False]
    assert card.primary_row.no_show_all is True
    assert card.secondary_row.no_show_all is True


def test_default_badge_hidden_when_not_default() -> None:
    card = _card(make_account_vm(is_default=False))
    assert card.default_badge.visible is False


def test_bar_levels_apply_hot_and_crit_classes() -> None:
    vm = make_account_vm(
        primary=make_bar(fraction=0.85, level="hot"),
        secondary=make_bar(window_label="7d", fraction=0.95, level="crit"),
    )
    card = _card(vm)

    assert "hot" in card.primary_bar.css_classes
    assert "crit" not in card.primary_bar.css_classes
    assert "crit" in card.secondary_bar.css_classes
    assert "hot" not in card.secondary_bar.css_classes


def test_broken_account_shows_err_badge_and_attention() -> None:
    vm = make_account_vm(
        health="broken",
        health_text="Needs repair",
        attention=True,
        primary_action="repair",
        primary_action_label="Repair…",
    )
    card = _card(vm)

    assert "attention" in card.widget.css_classes
    assert card.health_badge.visible is True
    assert card.health_badge.text == "Needs repair"
    assert "err" in card.health_badge.css_classes
    assert "ok" not in card.health_badge.css_classes


def test_unknown_health_shows_warn_badge() -> None:
    card = _card(make_account_vm(health="unknown", health_text="Checking"))
    assert card.health_badge.visible is True
    assert "warn" in card.health_badge.css_classes


def test_grok_without_primary_window_hides_primary_row() -> None:
    vm = make_account_vm(
        tool="grok",
        primary=None,
        secondary=make_bar(window_label="mo", fraction=0.3),
    )
    card = _card(vm)

    assert card.primary_row.visible is False
    assert card.secondary_row.visible is True
    assert card.secondary_window_label.text == "mo"


def test_set_as_default_lives_in_menu_not_primary_button() -> None:
    calls: list[tuple[Any, ...]] = []
    card = _card(make_account_vm(tool="codex", slug="work"), calls)

    assert card.primary_button.visible is False
    assert [label for label, _ in card.menu_items][0] == "Set as default"
    card.menu_items[0][1]()
    assert calls == [("set_default", "codex", "work")]


def test_primary_button_repair_dispatches_on_repair() -> None:
    calls: list[tuple[Any, ...]] = []
    vm = make_account_vm(
        tool="grok",
        slug="roy-grok",
        health="broken",
        health_text="Needs repair",
        attention=True,
        primary_action="repair",
        primary_action_label="Repair…",
    )
    card = _card(vm, calls)

    assert card.primary_button.text == "Repair…"
    card.primary_button.emit("clicked")
    assert calls == [("repair", "grok", "roy-grok")]


def test_no_primary_button_on_default_healthy_account() -> None:
    vm = make_account_vm(is_default=True, primary_action=None, primary_action_label="")
    card = _card(vm)
    assert card.primary_button.visible is False


def test_busy_set_default_makes_menu_item_insensitive() -> None:
    calls: list[tuple[Any, ...]] = []
    vm = make_account_vm(busy_actions=frozenset({"set_default"}))
    card = _card(vm, calls)

    assert card.primary_button.visible is False
    item = card._menu_action_widgets["set_default"]
    assert item.visible is True
    assert item.sensitive is False
    item.emit("activate")
    assert calls == []


def test_set_as_default_menu_item_hidden_when_already_default() -> None:
    card = _card(make_account_vm(is_default=True, primary_action=None, primary_action_label=""))
    assert card._menu_action_widgets["set_default"].visible is False


def test_set_as_default_menu_item_visible_for_broken_non_default_account() -> None:
    card = _card(
        make_account_vm(
            tool="codex",
            slug="spare",
            health="broken",
            health_text="Needs repair",
            attention=True,
            primary_action="repair",
            primary_action_label="Repair…",
        )
    )

    item = card._menu_action_widgets["set_default"]
    assert item.visible is True
    assert item.sensitive is True


def test_set_as_default_menu_item_insensitive_for_locked_non_default_account() -> None:
    card = _card(
        make_account_vm(tool="codex", slug="spare", locked=True)
    )

    item = card._menu_action_widgets["set_default"]
    assert item.visible is True
    assert item.sensitive is False


def test_busy_reauthenticate_makes_repair_button_insensitive() -> None:
    vm = make_account_vm(
        health="broken",
        health_text="Needs repair",
        attention=True,
        primary_action="repair",
        primary_action_label="Repair…",
        busy_actions=frozenset({"reauthenticate"}),
    )
    card = _card(vm)
    assert card.primary_button.sensitive is False


def test_menu_items_labels_and_dispatch() -> None:
    calls: list[tuple[Any, ...]] = []
    card = _card(make_account_vm(tool="claude", slug="shared"), calls)

    assert [label for label, _ in card.menu_items] == [
        "Set as default",
        "Reload",
        "Set limits…",
        "Re-authenticate…",
        "Rename…",
        "Remove…",
        "Move to Gateway…",
    ]
    for _, dispatch in card.menu_items:
        dispatch()
    assert calls == [
        ("set_default", "claude", "shared"),
        ("reload", "claude", "shared"),
        ("set_limits", "claude", "shared"),
        ("repair", "claude", "shared"),
        ("rename", "claude", "shared"),
        ("remove", "claude", "shared"),
        ("gateway", "claude", "shared", "migrate"),
    ]


def test_update_mutates_in_place() -> None:
    calls: list[tuple[Any, ...]] = []
    card = _card(make_account_vm(), calls)
    widget = card.widget
    alias_label = card.alias_label
    primary_bar = card.primary_bar
    primary_button = card.primary_button

    card.update(
        make_account_vm(
            alias="Renamed",
            plan_text="pro",
            is_default=True,
            health="broken",
            health_text="Needs repair",
            attention=True,
            primary=make_bar(fraction=0.97, level="crit"),
            checked_text="⟳ 5m ago (stale)",
            primary_action="repair",
            primary_action_label="Repair…",
        )
    )

    assert card.widget is widget
    assert card.alias_label is alias_label
    assert card.primary_bar is primary_bar
    assert card.primary_button is primary_button
    assert alias_label.text == "Renamed"
    assert card.plan_label.text == "pro"
    assert card.checked_label.text == "⟳ 5m ago (stale)"
    assert card.default_badge.visible is True
    assert "attention" in widget.css_classes
    assert "err" in card.health_badge.css_classes
    assert "ok" not in card.health_badge.css_classes
    assert primary_bar.fraction == 0.97
    assert "crit" in primary_bar.css_classes
    assert primary_button.text == "Repair…"
    primary_button.emit("clicked")
    assert calls == [("repair", "codex", "work")]


def test_update_clears_stale_level_and_hides_primary_button() -> None:
    card = _card(
        make_account_vm(primary=make_bar(fraction=0.85, level="hot"))
    )
    assert "hot" in card.primary_bar.css_classes

    card.update(make_account_vm(primary_action=None, primary_action_label=""))

    assert "hot" not in card.primary_bar.css_classes
    assert card.primary_button.visible is False


def test_quota_row_shows_cap_as_stop_at_left_percent() -> None:
    vm = make_account_vm(
        secondary=make_bar(
            window_label="7d",
            fraction=0.12,
            left_pct=12,
            percent_text="12% left",
            cap_stop_at_pct=10,
        ),
    )
    card = _card(vm)
    label = card.secondary_display_label.text
    assert label.endswith("stop at 10% left")
    assert "↺" in label


def test_lock_button_reflects_state_and_dispatches_toggle() -> None:
    calls: list[tuple[Any, ...]] = []
    card = _card(make_account_vm(tool="claude", slug="owner", locked=True), calls)

    assert "locked" in card.widget.css_classes
    assert "locked" in card.lock_button.css_classes
    assert card.lock_button.text == "🔒"
    assert card.lock_button.tooltip_text == "Unlock account for new sessions"

    card.lock_button.emit("clicked")

    assert calls == [("toggle_lock", "claude", "owner")]

    card.update(make_account_vm(tool="claude", slug="owner", locked=False))
    assert "locked" not in card.widget.css_classes
    assert card.lock_button.text == "🔓"
    assert card.lock_button.tooltip_text == "Lock account against new sessions"


def test_locked_card_disables_reload_and_reauthentication_only() -> None:
    card = _card(make_account_vm(tool="claude", slug="owner", locked=True))

    assert card._menu_action_widgets["reload"].sensitive is False
    assert card._menu_action_widgets["reauthenticate"].sensitive is False
    assert card._menu_action_widgets["set_limits"].sensitive is True
    assert card._menu_action_widgets["rename"].sensitive is True
    assert card._menu_action_widgets["remove"].sensitive is True


def test_gateway_menu_updates_in_place_with_custody_state() -> None:
    calls: list[tuple[Any, ...]] = []
    card = _card(make_account_vm(gateway_state="native"), calls)
    assert [label for label, _ in card.menu_items][-1] == "Move to Gateway…"

    card.update(make_account_vm(gateway_state="testing"))
    assert card.gateway_badge.visible is True
    assert card.gateway_badge.text == "GATEWAY TESTING"
    assert [label for label, _ in card.menu_items][-2:] == [
        "Activate Gateway",
        "Cancel Gateway migration",
    ]
    card.menu_items[-2][1]()
    card.menu_items[-1][1]()
    assert calls[-2:] == [
        ("gateway", "codex", "work", "activate"),
        ("gateway", "codex", "work", "cancel"),
    ]

    card.update(make_account_vm(gateway_state="active"))
    assert card.gateway_badge.text == "GATEWAY"
    assert [label for label, _ in card.menu_items][-1] == "Return to native…"
    card.menu_items[-1][1]()
    assert calls[-1] == ("gateway", "codex", "work", "rollback")

    card.update(make_account_vm(gateway_state="paused"))
    assert card.gateway_badge.text == "GATEWAY PAUSED"
    assert [label for label, _ in card.menu_items][-1] == "Continue return to native…"

    card.update(make_account_vm(gateway_state="native"))
    assert card.gateway_badge.visible is False


def test_gateway_menu_is_disabled_when_account_is_locked_or_busy() -> None:
    card = _card(make_account_vm(locked=True, gateway_state="native"))
    assert card._menu_action_widgets["gateway_primary"].sensitive is False
    card.update(make_account_vm(gateway_state="testing", busy_actions=frozenset({"gateway"})))
    assert card._menu_action_widgets["gateway_primary"].sensitive is False
    assert card._menu_action_widgets["gateway_cancel"].sensitive is False
