"""Billing: plan limits, run quota, metering, the summary, and the webhook."""

from __future__ import annotations

import uuid

from legate.billing.plans import PLANS
from legate.billing.service import current_period
from legate.config import get_settings
from legate.db.models.usage import UsageRecord


def _enable_billing():
    get_settings().billing_enabled = True


def test_plan_limit_blocks_creating_too_many_agents(client, helpers):
    _enable_billing()
    owner = helpers.bootstrap_owner(client)
    token = owner["access_token"]
    limit = PLANS["free"].max_agents

    for i in range(limit):
        assert (
            client.post(
                "/agents", json={"name": f"A{i}", "model": "m"}, headers=helpers.headers(token)
            ).status_code
            == 201
        )
    over = client.post(
        "/agents", json={"name": "over", "model": "m"}, headers=helpers.headers(token)
    )
    assert over.status_code == 402
    assert "Free plan" in over.json()["detail"]


def test_member_limit_enforced(client, helpers):
    _enable_billing()
    owner = helpers.bootstrap_owner(client)
    token = owner["access_token"]
    # Free plan allows 3 members; the owner is the first.
    helpers.register(client, "m2@x.com")
    helpers.register(client, "m3@x.com")
    helpers.register(client, "m4@x.com")
    assert (
        client.post(
            "/members/invite",
            json={"email": "m2@x.com", "role": "viewer"},
            headers=helpers.headers(token),
        ).status_code
        == 201
    )
    assert (
        client.post(
            "/members/invite",
            json={"email": "m3@x.com", "role": "viewer"},
            headers=helpers.headers(token),
        ).status_code
        == 201
    )
    over = client.post(
        "/members/invite",
        json={"email": "m4@x.com", "role": "viewer"},
        headers=helpers.headers(token),
    )
    assert over.status_code == 402


def test_run_quota_enforced(client, helpers, session_factory):
    _enable_billing()
    owner = helpers.bootstrap_owner(client)
    token = owner["access_token"]
    agent = helpers.create_agent(client, token)

    # Pre-fill this period's run usage to the plan cap.
    session = session_factory()
    session.add(
        UsageRecord(
            workspace_id=uuid.UUID(owner["workspace"]["id"]),
            metric="runs",
            quantity=PLANS["free"].max_runs_per_month,
            period=current_period(),
        )
    )
    session.commit()
    session.close()

    blocked = client.post(
        f"/agents/{agent['id']}/run", json={"input": ""}, headers=helpers.headers(token)
    )
    assert blocked.status_code == 402
    assert "quota" in blocked.json()["detail"]


def test_usage_is_metered_and_summarized(client, helpers, set_agent_responses):
    owner = helpers.bootstrap_owner(client)
    token = owner["access_token"]
    agent = helpers.create_agent(client, token)
    set_agent_responses(['{"thought":"t","action":"final","args":{"output":"ok"}}'])
    helpers.run_agent(client, token, agent["id"])

    usage = client.get("/usage", headers=helpers.headers(token)).json()
    assert usage["plan"]["name"] == "free"
    assert usage["usage"]["runs"] == 1
    assert usage["usage"]["agents"] == 1


def test_billing_summary_lists_plans(client, helpers):
    owner = helpers.bootstrap_owner(client)
    resp = client.get("/billing", headers=helpers.headers(owner["access_token"]))
    assert resp.status_code == 200
    body = resp.json()
    assert body["plan"]["name"] == "free"
    assert {p["name"] for p in body["available_plans"]} == {"free", "pro", "enterprise"}


def test_stripe_webhook_upgrades_plan(client, helpers):
    owner = helpers.bootstrap_owner(client)
    token = owner["access_token"]
    ws_id = owner["workspace"]["id"]

    event = {
        "type": "checkout.session.completed",
        "data": {"object": {"metadata": {"workspace_id": ws_id, "plan": "pro"}}},
    }
    resp = client.post("/billing/webhook", json=event)
    assert resp.status_code == 200 and resp.json()["plan"] == "pro"

    billing = client.get("/billing", headers=helpers.headers(token)).json()
    assert billing["plan"]["name"] == "pro"


def test_no_enforcement_when_billing_disabled(client, helpers):
    # billing_enabled defaults False -> far beyond the free plan is fine.
    owner = helpers.bootstrap_owner(client)
    token = owner["access_token"]
    for i in range(PLANS["free"].max_agents + 2):
        assert (
            client.post(
                "/agents", json={"name": f"A{i}", "model": "m"}, headers=helpers.headers(token)
            ).status_code
            == 201
        )
