"""
BIBIVIDI — Badge SVG tests (TODO-16)
Tests for GET /bibividi/badge.svg endpoint.
"""
from __future__ import annotations

from contextlib import ExitStack
from unittest.mock import AsyncMock
from unittest.mock import patch as _patch

import pytest
from fastapi.testclient import TestClient

from bvd.core.proxy import app


def _make_client():
    return TestClient(app, raise_server_exceptions=True)


_EMPTY_SUMMARY = {
    "calls": 0, "tokens_saved": 0, "tokens_in": 0,
    "saving_ratio": 0.0, "estimated_usd_saved": 0.0, "co2_grams": 0.0,
}

_SUMMARY_WITH_DATA = {
    "calls": 42, "tokens_saved": 1_500_000, "tokens_in": 2_000_000,
    "saving_ratio": 0.75, "estimated_usd_saved": 1.5, "co2_grams": 4500.0,
}


@pytest.mark.asyncio
async def test_badge_returns_svg():
    """GET /bibividi/badge.svg returns SVG content-type."""
    with ExitStack() as stack:
        stack.enter_context(_patch("bvd.engine.stats.stats_tracker.monthly_summary",
                                   AsyncMock(return_value=_EMPTY_SUMMARY)))
        stack.enter_context(_patch("bvd.engine.library.library.init", AsyncMock()))
        stack.enter_context(_patch("bvd.notifier.digest_scheduler", AsyncMock()))
        client = _make_client()
        resp = client.get("/bibividi/badge.svg")

    assert resp.status_code == 200
    assert "image/svg+xml" in resp.headers["content-type"]
    assert "<svg" in resp.text


@pytest.mark.asyncio
async def test_badge_shows_tokens_saved():
    """Badge SVG body contains the formatted tokens-saved figure."""
    with ExitStack() as stack:
        stack.enter_context(_patch("bvd.engine.stats.stats_tracker.monthly_summary",
                                   AsyncMock(return_value=_SUMMARY_WITH_DATA)))
        stack.enter_context(_patch("bvd.engine.library.library.init", AsyncMock()))
        stack.enter_context(_patch("bvd.notifier.digest_scheduler", AsyncMock()))
        client = _make_client()
        resp = client.get("/bibividi/badge.svg")

    assert resp.status_code == 200
    # 1_500_000 → "1.5M tokens saved"
    assert "1.5M tokens saved" in resp.text


@pytest.mark.asyncio
async def test_badge_no_token_required_when_not_configured():
    """Badge is public (no token needed) when BIBIVIDI_BADGE_TOKEN is unset."""
    with ExitStack() as stack:
        stack.enter_context(_patch("bvd.engine.stats.stats_tracker.monthly_summary",
                                   AsyncMock(return_value=_EMPTY_SUMMARY)))
        stack.enter_context(_patch("bvd.config.settings.badge_token", None))
        stack.enter_context(_patch("bvd.engine.library.library.init", AsyncMock()))
        stack.enter_context(_patch("bvd.notifier.digest_scheduler", AsyncMock()))
        client = _make_client()
        resp = client.get("/bibividi/badge.svg")

    assert resp.status_code == 200


@pytest.mark.asyncio
async def test_badge_token_required_when_configured():
    """Badge returns 403 when token is configured but wrong/missing."""
    with ExitStack() as stack:
        stack.enter_context(_patch("bvd.engine.stats.stats_tracker.monthly_summary",
                                   AsyncMock(return_value=_EMPTY_SUMMARY)))
        stack.enter_context(_patch("bvd.config.settings.badge_token", "secret-token"))
        stack.enter_context(_patch("bvd.engine.library.library.init", AsyncMock()))
        stack.enter_context(_patch("bvd.notifier.digest_scheduler", AsyncMock()))
        client = _make_client()
        resp_no_token = client.get("/bibividi/badge.svg")
        resp_wrong = client.get("/bibividi/badge.svg?token=wrong")
        resp_correct = client.get("/bibividi/badge.svg?token=secret-token")

    assert resp_no_token.status_code == 403
    assert resp_wrong.status_code == 403
    assert resp_correct.status_code == 200


@pytest.mark.asyncio
async def test_badge_co2_shown_in_kg_above_threshold():
    """CO₂ label switches to kg when ≥ 1000g."""
    summary = {**_SUMMARY_WITH_DATA, "co2_grams": 4500.0}
    with ExitStack() as stack:
        stack.enter_context(_patch("bvd.engine.stats.stats_tracker.monthly_summary",
                                   AsyncMock(return_value=summary)))
        stack.enter_context(_patch("bvd.engine.library.library.init", AsyncMock()))
        stack.enter_context(_patch("bvd.notifier.digest_scheduler", AsyncMock()))
        client = _make_client()
        resp = client.get("/bibividi/badge.svg")

    assert resp.status_code == 200
    assert "4.5kg CO" in resp.text
