from __future__ import annotations

import sys
from pathlib import Path

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

from health_client import AccountSnapshot, HealthStatus
from ui.view_model import AccountInput, ProviderInput, build_dashboard_vm

NOW = 1_000_000.0


def _snapshot(
    status=HealthStatus.OK,
    primary=None,
    secondary=None,
    primary_reset_at=None,
    secondary_reset_at=None,
):
    return AccountSnapshot(
        status=status,
        primary_used_pct=primary,
        secondary_used_pct=secondary,
        primary_reset_at=primary_reset_at,
        secondary_reset_at=secondary_reset_at,
    )


def _account(
    slug,
    *,
    tool="codex",
    alias=None,
    plan="pro",
    is_default=False,
    snapshot=None,
    checked_at=NOW - 12,
    busy_actions=frozenset(),
    locked=False,
):
    return AccountInput(
        tool=tool,
        slug=slug,
        alias=alias if alias is not None else slug,
        plan=plan,
        is_default=is_default,
        snapshot=snapshot,
        checked_at=checked_at,
        busy_actions=busy_actions,
        locked=locked,
    )


def _provider(accounts, *, tool="codex", label="Codex"):
    return ProviderInput(tool=tool, label=label, accounts=tuple(accounts))


def _build(
    providers,
    *,
    last_used_tab=None,
    warning_threshold_pct=15,
    dismissed_alert_keys=frozenset(),
):
    return build_dashboard_vm(
        providers,
        now=NOW,
        last_used_tab=last_used_tab,
        warning_threshold_pct=warning_threshold_pct,
        dismissed_alert_keys=dismissed_alert_keys,
    )


def test_breach_alert_switch_picks_lowest_5h_healthy_same_provider():
    provider = _provider(
        [
            _account(
                "personal",
                is_default=True,
                snapshot=_snapshot(
                    primary=92, secondary=40, primary_reset_at=NOW + 44 * 60
                ),
            ),
            _account("other", snapshot=_snapshot(primary=55, secondary=10)),
            _account("work", snapshot=_snapshot(primary=42, secondary=67)),
        ]
    )

    vm = _build([provider])

    assert len(vm.alerts.alerts) == 1
    alert = vm.alerts.alerts[0]
    assert alert.kind == "breach"
    assert alert.tool == "codex"
    assert alert.slug == "personal"
    assert alert.title_text == "codex/personal 8% left of 5h window"
    assert alert.detail_text == "resets in 44m · work has 58% left"
    assert alert.action == "switch"
    assert alert.action_label == "Switch to work"
    assert alert.action_slug == "work"


def test_breach_switch_label_uses_alias_and_action_slug_uses_slug():
    provider = _provider(
        [
            _account("hot", snapshot=_snapshot(primary=95, secondary=30)),
            _account("w-slug", alias="Work", snapshot=_snapshot(primary=10, secondary=5)),
        ]
    )

    alert = _build([provider]).alerts.alerts[0]

    assert alert.action_label == "Switch to Work"
    assert alert.action_slug == "w-slug"


def test_breach_switch_skips_broken_candidate_and_tie_breaks_on_lower_secondary():
    provider = _provider(
        [
            _account("hot", snapshot=_snapshot(primary=90, secondary=10)),
            _account("broken", snapshot=_snapshot(HealthStatus.BROKEN)),
            _account("tie-high", snapshot=_snapshot(primary=40, secondary=70)),
            _account("tie-low", snapshot=_snapshot(primary=40, secondary=20)),
        ]
    )

    alerts = _build([provider]).alerts.alerts
    breach = [alert for alert in alerts if alert.kind == "breach"][0]

    assert breach.action_slug == "tie-low"


def test_locked_account_is_not_offered_as_default_or_switch_target():
    provider = _provider(
        [
            _account("hot", is_default=True, snapshot=_snapshot(primary=95, secondary=30)),
            _account("locked", locked=True, snapshot=_snapshot(primary=1, secondary=1)),
            _account("open", snapshot=_snapshot(primary=20, secondary=10)),
        ]
    )

    vm = _build([provider])
    locked_vm = vm.providers[0].accounts[1]
    breach = vm.alerts.alerts[0]

    assert locked_vm.locked is True
    assert locked_vm.primary_action is None
    assert breach.action_slug == "open"


def test_locked_broken_account_does_not_offer_reauthentication():
    provider = _provider(
        [
            _account(
                "locked",
                locked=True,
                snapshot=_snapshot(HealthStatus.BROKEN),
            )
        ]
    )

    locked_vm = _build([provider]).providers[0].accounts[0]

    assert locked_vm.health == "broken"
    assert locked_vm.primary_action is None
    assert locked_vm.primary_action_label == ""


def test_breach_no_candidate_renders_alert_without_action():
    provider = _provider(
        [
            _account("only", snapshot=_snapshot(primary=99, secondary=50)),
            _account("dead", snapshot=_snapshot(HealthStatus.BROKEN)),
        ]
    )

    vm = _build([provider])
    breach = [alert for alert in vm.alerts.alerts if alert.kind == "breach"][0]

    assert breach.action is None
    assert breach.action_label == ""
    assert breach.action_slug is None


def test_grok_breach_uses_secondary_fallback_and_billing_period_label():
    provider = _provider(
        [
            _account(
                "roy-grok",
                tool="grok",
                snapshot=_snapshot(secondary=96, secondary_reset_at=NOW + 60),
            ),
            _account("spare-a", tool="grok", snapshot=_snapshot(secondary=31)),
            _account("spare-b", tool="grok", snapshot=_snapshot(secondary=64)),
        ],
        tool="grok",
        label="Grok",
    )

    vm = _build([provider])

    alert = vm.alerts.alerts[0]
    assert alert.kind == "breach"
    assert alert.title_text == "grok/roy-grok 4% left of billing period"
    assert alert.detail_text == "resets in 1m · spare-a has 69% left"
    assert alert.action == "switch"
    assert alert.action_slug == "spare-a"

    spare = vm.providers[0].accounts[1]
    assert spare.primary is None
    assert spare.secondary is not None
    assert spare.secondary.window_label == "mo"


def test_broken_alert_repair_and_sorts_before_breach():
    provider = _provider(
        [
            _account("hot", snapshot=_snapshot(primary=90, secondary=10)),
            _account("expired", snapshot=_snapshot(HealthStatus.BROKEN)),
        ]
    )

    alerts = _build([provider]).alerts.alerts

    assert [alert.kind for alert in alerts] == ["broken", "breach"]
    broken = alerts[0]
    assert broken.title_text == "codex/expired auth expired"
    assert broken.detail_text == "health checks paused"
    assert broken.action == "repair"
    assert broken.action_label == "Repair…"
    assert broken.action_slug is None


def test_alert_has_stable_dismissal_key():
    provider = _provider([_account("expired", snapshot=_snapshot(HealthStatus.BROKEN))])

    alert = _build([provider]).alerts.alerts[0]

    assert alert.dismissal_key == ("broken", "codex", "expired")


def test_dismissed_alert_is_excluded_from_alerts_badge_and_empty_state():
    provider = _provider(
        [
            _account("hot", snapshot=_snapshot(primary=90, secondary=10)),
            _account("expired", snapshot=_snapshot(HealthStatus.BROKEN)),
        ]
    )

    vm = _build([provider], dismissed_alert_keys=frozenset({("broken", "codex", "expired")}))

    assert [(alert.kind, alert.slug) for alert in vm.alerts.alerts] == [("breach", "hot")]
    assert vm.tabs[0].badge_count == 1
    assert vm.tabs[0].badge_level == "warn"
    assert vm.active_tab == "alerts"


def test_breach_title_uses_worst_breached_window():
    provider = _provider(
        [_account("acct", snapshot=_snapshot(primary=88, secondary=97))]
    )

    alert = _build([provider]).alerts.alerts[0]

    assert alert.title_text == "codex/acct 3% left of 7d window"


def test_7d_breach_target_reports_7d_headroom_not_5h():
    provider = _provider(
        [
            _account("avi", snapshot=_snapshot(primary=34, secondary=100)),
            _account("rafa", snapshot=_snapshot(primary=75, secondary=100)),
            _account("roy", snapshot=_snapshot(primary=4, secondary=64)),
        ]
    )

    alert = _build([provider]).alerts.alerts[0]

    assert alert.title_text == "codex/avi 0% left of 7d window"
    assert alert.detail_text == "roy has 36% left"
    assert alert.action_slug == "roy"


def test_unknown_status_with_fresh_pcts_is_treated_as_ok():
    provider = _provider(
        [
            _account(
                "quiet", snapshot=_snapshot(HealthStatus.UNKNOWN, primary=92, secondary=40)
            ),
            _account(
                "spare", snapshot=_snapshot(HealthStatus.UNKNOWN, primary=10, secondary=5)
            ),
        ]
    )

    vm = _build([provider])

    assert vm.alerts.alerts[0].kind == "breach"
    assert vm.alerts.alerts[0].action_slug == "spare"


def test_unknown_status_with_stale_pcts_remains_checking():
    provider = _provider(
        [
            _account(
                "stale",
                snapshot=_snapshot(HealthStatus.UNKNOWN, primary=53, secondary=82),
                checked_at=NOW - 301,
            )
        ]
    )

    account = _build([provider]).providers[0].accounts[0]

    assert account.health == "unknown"
    assert account.health_text == "Checking"
    assert account.checked_text == "⟳ 5m ago (stale)"


def test_badge_counts_and_levels():
    codex = _provider(
        [
            _account("hot", snapshot=_snapshot(primary=90, secondary=10)),
            _account("ok", snapshot=_snapshot(primary=10, secondary=10)),
        ]
    )
    claude = _provider(
        [_account("dead", tool="claude", snapshot=_snapshot(HealthStatus.BROKEN))],
        tool="claude",
        label="Claude Code",
    )
    grok = _provider(
        [_account("fine", tool="grok", snapshot=_snapshot(secondary=20))],
        tool="grok",
        label="Grok",
    )

    vm = _build([codex, claude, grok])

    alerts_tab, codex_tab, claude_tab, grok_tab = vm.tabs
    assert alerts_tab.id == "alerts"
    assert alerts_tab.label == "⚠ Alerts"
    assert alerts_tab.badge_count == 2
    assert alerts_tab.badge_level == "err"
    assert (codex_tab.badge_count, codex_tab.badge_level) == (1, "warn")
    assert (claude_tab.badge_count, claude_tab.badge_level) == (1, "err")
    assert (grok_tab.badge_count, grok_tab.badge_level) == (0, "")


def test_bar_levels_ok_hot_crit_follow_threshold():
    provider = _provider(
        [_account("acct", snapshot=_snapshot(primary=92, secondary=80))]
    )
    account = _build([provider]).providers[0].accounts[0]
    assert account.primary is not None and account.primary.level == "crit"
    assert account.secondary is not None and account.secondary.level == "hot"
    assert account.attention is True

    calm = _provider([_account("acct", snapshot=_snapshot(primary=42, secondary=10))])
    account = _build([calm]).providers[0].accounts[0]
    assert account.primary is not None and account.primary.level == "ok"
    assert account.attention is False

    wide = _provider([_account("acct", snapshot=_snapshot(primary=75, secondary=10))])
    account = _build([wide], warning_threshold_pct=30).providers[0].accounts[0]
    assert account.primary is not None and account.primary.level == "crit"


def test_quota_bar_formatted_strings():
    provider = _provider(
        [
            _account(
                "acct",
                snapshot=_snapshot(
                    primary=42,
                    secondary=67,
                    primary_reset_at=NOW + 2 * 3600 + 10 * 60,
                    secondary_reset_at=NOW + 3 * 86400 + 4 * 3600,
                ),
            )
        ]
    )

    account = _build([provider]).providers[0].accounts[0]

    assert account.primary.window_label == "5h"
    assert account.primary.fraction == 0.58
    assert account.primary.left_pct == 58
    assert account.primary.percent_text == "58% left"
    assert account.primary.reset_text == "↺ 2h10m"
    assert account.secondary.window_label == "7d"
    assert account.secondary.percent_text == "33% left"
    assert account.secondary.reset_text == "↺ 3d4h"


def test_quota_bar_shows_left_percent_and_cap_stop_at():
    from dataclasses import replace

    from limit_warning import WINDOW_7D

    account = _account(
        "zync2",
        snapshot=_snapshot(primary=None, secondary=88),
    )
    account = replace(account, account_caps={WINDOW_7D: 10})
    provider = _provider([account])
    vm = _build([provider]).providers[0].accounts[0]

    assert vm.secondary is not None
    assert vm.secondary.percent_text == "12% left"
    assert vm.secondary.cap_stop_at_pct == 10


def test_reset_text_empty_when_reset_at_missing():
    provider = _provider([_account("acct", snapshot=_snapshot(primary=42, secondary=1))])
    account = _build([provider]).providers[0].accounts[0]
    assert account.primary.reset_text == ""


def test_reset_text_empty_when_reset_is_expired():
    provider = _provider(
        [
            _account(
                "acct",
                snapshot=_snapshot(primary=42, primary_reset_at=NOW - 1),
            )
        ]
    )
    account = _build([provider]).providers[0].accounts[0]
    assert account.primary.reset_text == ""


def test_checked_text_and_refresh_text_formats():
    provider = _provider(
        [
            _account("fresh", snapshot=_snapshot(primary=1, secondary=1), checked_at=NOW - 12),
            _account("stale", snapshot=_snapshot(primary=1, secondary=1), checked_at=NOW - 300),
            _account("hours", snapshot=_snapshot(primary=1, secondary=1), checked_at=NOW - 7200),
            _account("days", snapshot=_snapshot(primary=1, secondary=1), checked_at=NOW - 172800),
            _account("never", snapshot=None, checked_at=None),
        ]
    )

    vm = _build([provider])
    fresh, stale, hours, days, never = vm.providers[0].accounts

    assert fresh.checked_text == "⟳ 12s ago"
    assert stale.checked_text == "⟳ 5m ago (stale)"
    assert hours.checked_text == "⟳ 2h ago (stale)"
    assert days.checked_text == "⟳ 2d ago (stale)"
    assert never.checked_text == "never refreshed"
    assert vm.refresh_text == "⟳ 12s ago"


def test_refresh_text_never_without_checked_accounts():
    provider = _provider([_account("acct", snapshot=None, checked_at=None)])
    assert _build([provider]).refresh_text == "⟳ never"


def test_primary_action_contextual():
    provider = _provider(
        [
            _account("main", is_default=True, snapshot=_snapshot(primary=1, secondary=1)),
            _account("spare", snapshot=_snapshot(primary=1, secondary=1)),
            _account("dead", snapshot=_snapshot(HealthStatus.BROKEN)),
            _account("checking", snapshot=None, checked_at=None),
        ]
    )

    main, spare, dead, checking = _build([provider]).providers[0].accounts

    assert (main.primary_action, main.primary_action_label) == (None, "")
    assert (spare.primary_action, spare.primary_action_label) == (
        "set_default",
        "Set as default",
    )
    assert (dead.primary_action, dead.primary_action_label) == ("repair", "Repair…")
    assert (checking.primary_action, checking.primary_action_label) == (None, "")
    assert dead.health_text == "Needs repair"
    assert checking.health_text == "Checking"
    assert spare.health_text == "Healthy"


def test_active_tab_rules():
    healthy = _provider([_account("ok", snapshot=_snapshot(primary=1, secondary=1))])
    claude = _provider(
        [_account("c", tool="claude", snapshot=_snapshot(primary=1, secondary=1))],
        tool="claude",
        label="Claude Code",
    )
    alerting = _provider([_account("hot", snapshot=_snapshot(primary=99, secondary=1))])

    assert _build([alerting], last_used_tab="codex").active_tab == "alerts"
    assert _build([healthy, claude], last_used_tab="claude").active_tab == "claude"
    assert _build([healthy, claude], last_used_tab="bogus").active_tab == "codex"
    assert _build([healthy, claude], last_used_tab=None).active_tab == "codex"
    assert _build([], last_used_tab="codex").active_tab == "alerts"


def test_empty_state_and_healthy_summary_lines():
    codex = _provider(
        [
            _account("work", is_default=True, snapshot=_snapshot(primary=42, secondary=67)),
            _account("spare", snapshot=_snapshot(primary=12, secondary=30)),
        ]
    )
    grok = _provider(
        [_account("g", tool="grok", snapshot=_snapshot(secondary=31))],
        tool="grok",
        label="Grok",
    )

    vm = _build([codex, grok])

    assert vm.alerts.alerts == ()
    assert vm.alerts.empty_heading == "All good ✓"
    assert (
        vm.alerts.empty_detail
        == "3 accounts · lowest 5h 58% left · lowest 7d 33% left · lowest mo 69% left"
    )
    lines = vm.alerts.healthy_lines
    assert [line.text_left for line in lines] == [
        "✓ codex/work ★",
        "✓ codex/spare",
        "✓ grok/g",
    ]
    assert lines[0].text_right == "5h 58% left · 7d 33% left"
    assert lines[2].text_right == "mo 69% left"


def test_alerting_accounts_excluded_from_healthy_lines_and_empty_state_suppressed():
    provider = _provider(
        [
            _account("hot", snapshot=_snapshot(primary=99, secondary=1)),
            _account("calm", snapshot=_snapshot(primary=5, secondary=5)),
        ]
    )

    vm = _build([provider])

    assert vm.alerts.empty_heading == ""
    assert vm.alerts.empty_detail == ""
    assert [line.text_left for line in vm.alerts.healthy_lines] == ["✓ codex/calm"]


def test_provider_tab_vm_and_add_tools():
    codex = _provider([_account("a", snapshot=_snapshot(primary=1, secondary=1))])
    claude = _provider([], tool="claude", label="Claude Code")

    vm = _build([codex, claude])

    assert vm.providers[0].add_label == "＋ Add Codex account"
    assert vm.providers[1].add_label == "＋ Add Claude Code account"
    assert vm.add_tools == (("codex", "Codex"), ("claude", "Claude Code"))
    assert vm.providers[0].accounts[0].plan_text == "pro"


def test_busy_actions_and_plan_text_passthrough():
    provider = _provider(
        [
            _account(
                "a",
                plan=None,
                snapshot=_snapshot(primary=1, secondary=1),
                busy_actions=frozenset({"reload"}),
            )
        ]
    )

    account = _build([provider]).providers[0].accounts[0]

    assert account.plan_text == "unknown"
    assert account.busy_actions == frozenset({"reload"})


def test_unknown_health_needs_attention_and_is_not_listed_healthy():
    provider = _provider(
        [
            _account("ghost", snapshot=None, checked_at=None),
            _account("ok", snapshot=_snapshot(primary=10, secondary=10)),
        ]
    )

    vm = _build([provider])

    ghost = vm.providers[0].accounts[0]
    assert (ghost.health, ghost.health_text) == ("unknown", "Checking")
    assert ghost.attention is True
    assert (vm.tabs[1].badge_count, vm.tabs[1].badge_level) == (1, "warn")
    assert vm.tabs[0].badge_count == 0
    assert vm.alerts.empty_heading == ""
    assert vm.alerts.empty_detail == ""
    assert [line.text_left for line in vm.alerts.healthy_lines] == [
        "… codex/ghost",
        "✓ codex/ok",
    ]
    assert vm.alerts.healthy_lines[0].text_right == "checking"


def test_switch_target_skips_current_default_and_breached_candidates():
    provider = _provider(
        [
            _account("hot", snapshot=_snapshot(primary=95, secondary=10)),
            _account("boss", is_default=True, snapshot=_snapshot(primary=5, secondary=5)),
            _account("warm", snapshot=_snapshot(primary=88, secondary=10)),
            _account("calm", snapshot=_snapshot(primary=40, secondary=10)),
        ]
    )

    breach = _build([provider]).alerts.alerts[0]

    assert breach.slug == "hot"
    assert breach.action_slug == "calm"


def test_switch_target_none_when_only_default_or_breached_remain():
    provider = _provider(
        [
            _account("hot", snapshot=_snapshot(primary=95, secondary=10)),
            _account("boss", is_default=True, snapshot=_snapshot(primary=5, secondary=5)),
        ]
    )

    breach = _build([provider]).alerts.alerts[0]

    assert breach.action is None
    assert breach.action_label == ""
    assert breach.action_slug is None


def test_zero_accounts_empty_state_prompts_add_account():
    vm = _build([_provider([])])

    assert vm.alerts.empty_heading == "No accounts yet"
    assert vm.alerts.empty_detail == "Use ＋ Add account below to connect a provider"
    assert vm.alerts.healthy_lines == ()


def test_busy_add_tools_passthrough():
    vm = build_dashboard_vm(
        [_provider([])],
        now=NOW,
        last_used_tab=None,
        warning_threshold_pct=15,
        busy_add_tools=frozenset({"codex"}),
    )

    assert vm.busy_add_tools == frozenset({"codex"})
