"""Tests for the /billing CLI handler (cli.py::_show_billing).

Focus on the non-interactive (no live prompt_toolkit app) path — the same
discipline as the /credits non-interactive test: it must render text, never
invoke the modal (which would read the slash-worker's JSON-RPC stdin and hang).
Plus role/kill-switch gating and logged-out handling.
"""

from __future__ import annotations

from decimal import Decimal

import pytest

import agent.billing_view as bv
from agent.billing_view import BillingState, CardInfo, MonthlyCap
from cli import HermesCLI


@pytest.fixture
def cli():
    obj = HermesCLI.__new__(HermesCLI)  # bypass __init__ (no full app needed)
    obj._app = None  # non-interactive: forces the text path
    return obj


def _boom_modal(*a, **kw):
    raise AssertionError("modal must NOT be called in non-interactive mode")








# ── Card visibility + the add-card path (inline w/ NAS card-resolver) ──


def _scripted(*responses):
    it = iter(responses)

    def _modal(self, **kw):
        return next(it)

    return _modal


def test_topup_overview_splits_onetime_from_automatic_copy(cli, monkeypatch, capsys):
    # (c): the interactive /topup overview states the one-time-vs-automatic
    # distinction up front in each first sentence, and keeps "credits" out of the
    # dollars-only surface. Auto-reload OFF → the automatic line omits amounts.
    cli._app = object()  # interactive → reaches the split-copy explainer
    state = BillingState(
        logged_in=True, role="OWNER", balance_usd=Decimal("50"),
        cli_billing_enabled=True, charge_presets=(Decimal("25"),),
        card=CardInfo(brand="Visa", last4="4242"),
        portal_url="https://portal/billing",
    )
    monkeypatch.setattr(bv, "build_billing_state", lambda *a, **kw: state)
    # Overview prints the explainer, then the action modal → back out with "cancel".
    monkeypatch.setattr(HermesCLI, "_prompt_text_input_modal", _scripted("cancel"), raising=False)
    cli._show_billing("/topup")
    out = capsys.readouterr().out

    assert "Add funds now — a single charge, added to your balance today." in out
    assert "Refill when low — charges your card automatically when your balance falls below" in out
    # Dollars-only surface: no "credits" word leaks into /topup.
    assert "credits" not in out.lower()


def test_topup_automatic_copy_generic_when_amounts_missing(cli, monkeypatch, capsys):
    # (5): auto-reload "enabled" but amounts absent (partial response) → generic
    # copy, never "charges — automatically … below —.".
    from agent.billing_view import AutoReload

    cli._app = object()
    state = BillingState(
        logged_in=True, role="OWNER", balance_usd=Decimal("50"),
        cli_billing_enabled=True, charge_presets=(Decimal("25"),),
        card=CardInfo(brand="Visa", last4="4242"),
        auto_reload=AutoReload(enabled=True, threshold_usd=None, reload_to_usd=None),
        portal_url="https://portal/billing",
    )
    monkeypatch.setattr(bv, "build_billing_state", lambda *a, **kw: state)
    monkeypatch.setattr(HermesCLI, "_prompt_text_input_modal", _scripted("cancel"), raising=False)
    cli._show_billing("/topup")
    out = capsys.readouterr().out

    assert (
        "Refill when low — charges your card automatically when your balance "
        "falls below the amount you set."
    ) in out
    assert "charges — automatically" not in out








def test_buy_flow_no_card_back_abandons(cli, monkeypatch, capsys):
    cli._app = object()
    nocard = BillingState(
        logged_in=True, role="OWNER", cli_billing_enabled=True,
        charge_presets=(Decimal("25"),), card=None,
        portal_url="https://portal/billing",
    )
    calls = {"n": 0}

    def _no_fetch(*a, **kw):
        calls["n"] += 1
        return nocard

    monkeypatch.setattr(bv, "build_billing_state", _no_fetch)
    monkeypatch.setattr(HermesCLI, "_prompt_text_input_modal", _scripted("cancel"), raising=False)

    cli._billing_buy_flow(nocard)
    out = capsys.readouterr().out

    assert "Add a card first" in out
    assert "Cancelled. No funds added." in out
    assert calls["n"] == 0  # backed out before any re-check
