"""Codex account rate-limit normalization: bucket and window selection."""
import pytest

from device_gateway.control.codex_quota import (
    INVALID,
    normalize,
    normalize_notification,
    select_snapshot,
    select_window,
)


def window(used, resets=None, minutes=None):
    value = {"usedPercent": used}
    if resets is not None:
        value["resetsAt"] = resets
    if minutes is not None:
        value["windowDurationMins"] = minutes
    return value


def test_primary_only():
    quota = normalize({"rateLimitsByLimitId": {"codex": {"primary": window(28, 1700000000, 300)}}})
    assert quota.valid and quota.remaining_percent == 72
    assert quota.resets_at == 1700000000 and quota.window_minutes == 300


def test_secondary_only():
    quota = normalize({"rateLimitsByLimitId": {"codex": {"secondary": window(5, 1600000000, 10080)}}})
    assert quota.valid and quota.remaining_percent == 95
    assert quota.resets_at == 1600000000 and quota.window_minutes == 10080


def test_both_windows_select_tightest_remaining():
    quota = normalize({"rateLimitsByLimitId": {"codex": {
        "primary": window(28, 1700000000, 300),
        "secondary": window(61, 1600000000, 10080),
    }}})
    assert quota.valid and quota.remaining_percent == 39
    assert quota.resets_at == 1600000000 and quota.window_minutes == 10080


def test_equal_remaining_prefers_earlier_reset():
    quota = normalize({"rateLimitsByLimitId": {"codex": {
        "primary": window(50, 1900000000, 300),
        "secondary": window(50, 1500000000, 10080),
    }}})
    assert quota.remaining_percent == 50 and quota.resets_at == 1500000000


def test_equal_remaining_invalid_reset_defers_to_valid_reset():
    quota = normalize({"rateLimitsByLimitId": {"codex": {
        "primary": window(50, None, 300),
        "secondary": window(50, 1500000000, 10080),
    }}})
    assert quota.resets_at == 1500000000


def test_used_zero_and_hundred():
    assert normalize({"rateLimitsByLimitId": {"codex": {"primary": window(0)}}}).remaining_percent == 100
    assert normalize({"rateLimitsByLimitId": {"codex": {"primary": window(100)}}}).remaining_percent == 0


def test_out_of_range_used_percent_is_clamped():
    assert normalize({"rateLimitsByLimitId": {"codex": {"primary": window(140)}}}).remaining_percent == 0
    # Negative usage survives as a valid 100% remaining rather than invalid.
    assert normalize({"rateLimitsByLimitId": {"codex": {"primary": window(-5)}}}).remaining_percent == 100


def test_invalid_or_null_reset_keeps_quota_valid():
    quota = normalize({"rateLimitsByLimitId": {"codex": {"primary": window(40, None, None)}}})
    assert quota.valid and quota.remaining_percent == 60
    assert quota.resets_at is None and quota.window_minutes is None
    assert normalize({"rateLimitsByLimitId": {"codex": {"primary": window(40, "soon", "later")}}}).resets_at is None


def test_missing_used_percent_is_invalid():
    assert normalize({"rateLimitsByLimitId": {"codex": {"primary": {"resetsAt": 1}}}}) == INVALID
    assert normalize({"rateLimitsByLimitId": {"codex": {"primary": window(True)}}}) == INVALID
    assert normalize({"rateLimitsByLimitId": {"codex": {}}}) == INVALID
    assert normalize({}) == INVALID
    assert normalize(None) == INVALID


def test_bucket_prefers_rateLimitsByLimitId_codex():
    payload = {"rateLimitsByLimitId": {"codex": {"primary": window(10)}},
               "rateLimits": {"limitId": "codex", "primary": window(90)}}
    assert normalize(payload).remaining_percent == 90


def test_fallback_to_backward_compatible_rate_limits():
    assert normalize({"rateLimits": {"primary": window(25)}}).remaining_percent == 75
    assert normalize({"rateLimits": {"limitId": "codex", "primary": window(25)}}).remaining_percent == 75


def test_fallback_rejected_when_bucket_labels_another_limit():
    payload = {"rateLimitsByLimitId": {"other": {"primary": window(50)}},
               "rateLimits": {"limitId": "other", "primary": window(10)}}
    assert normalize(payload) == INVALID
    assert select_snapshot(payload) is None


def test_select_window_ignores_non_dict_entries():
    assert select_window({"primary": "nope", "secondary": window(30)})["remaining"] == 70
    assert select_window({"primary": "nope"}) is None
    assert select_window(None) is None


def test_notification_normalizes_sparse_update():
    quota = normalize_notification({"rateLimits": {"primary": window(45, 1700000000, 300),
                                                   "secondary": window(70, 1600000000, 10080)}})
    assert quota.valid and quota.remaining_percent == 30
    assert quota.resets_at == 1600000000
    # An empty or malformed sparse update stays invalid; callers keep prior state.
    assert normalize_notification({"rateLimits": {}}) == INVALID
    assert normalize_notification({}) == INVALID
    assert normalize_notification(None) == INVALID


def test_account_metadata_is_not_exposed():
    quota = normalize({"rateLimitsByLimitId": {"codex": {"primary": window(28, 1700000000, 300),
                                                        "planType": "pro", "limitName": "Codex"}},
                       "accountId": "secret", "rateLimitResetCredits": {"availableCount": 3}})
    assert set(quota.wire()) == {"codex_quota_valid", "codex_remaining_percent",
                                 "codex_resets_at", "codex_window_minutes"}
    assert "secret" not in repr(quota.wire())
    assert "pro" not in repr(quota.wire())