"""
BIBIVIDI — Mailer tests (TODO-18)
Tests for bvd/mailer.py: build_quarterly_email(), quarterly_summary().
"""
from __future__ import annotations

from datetime import UTC

import pytest

from bvd.mailer import QuarterlyEmail, _fmt_co2, _fmt_tokens, build_quarterly_email

# ── helpers ────────────────────────────────────────────────────────────────────

def _summary(**overrides) -> dict:
    base = {
        "calls": 500,
        "tokens_saved": 10_000_000,
        "tokens_in": 12_000_000,
        "savings_eur": 9.2,
        "bibividi_share_eur": 1.84,
        "co2_grams": 30_000.0,
        "top_skills": [
            {"skill_id": "pdf-clause-extractor", "uses": 200},
            {"skill_id": "csv-data-summarizer", "uses": 180},
            {"skill_id": "code-review-condenser", "uses": 120},
        ],
    }
    base.update(overrides)
    return base


# ── _fmt_tokens ────────────────────────────────────────────────────────────────

def test_fmt_tokens_small():
    assert _fmt_tokens(500) == "500"


def test_fmt_tokens_thousands():
    assert "K" in _fmt_tokens(5000)


def test_fmt_tokens_millions():
    assert "M" in _fmt_tokens(10_000_000)


def test_fmt_tokens_billions():
    assert "B" in _fmt_tokens(2_000_000_000)


# ── _fmt_co2 ──────────────────────────────────────────────────────────────────

def test_fmt_co2_grams():
    assert "g" in _fmt_co2(500.0)


def test_fmt_co2_kg():
    assert "kg" in _fmt_co2(5000.0)


def test_fmt_co2_tonnes():
    assert "t" in _fmt_co2(2_000_000.0)


# ── build_quarterly_email ──────────────────────────────────────────────────────

def test_returns_quarterly_email_dataclass():
    e = build_quarterly_email(_summary(), "2026-Q1")
    assert isinstance(e, QuarterlyEmail)
    assert e.subject
    assert e.html
    assert e.text


def test_subject_contains_quarter():
    e = build_quarterly_email(_summary(), "2026-Q1")
    assert "2026-Q1" in e.subject


def test_subject_contains_savings_eur():
    e = build_quarterly_email(_summary(savings_eur=9.20), "2026-Q1")
    assert "9.20" in e.subject


def test_html_is_valid():
    e = build_quarterly_email(_summary(), "2026-Q1")
    assert "<!DOCTYPE html>" in e.html
    assert "</html>" in e.html


def test_html_contains_quarter():
    e = build_quarterly_email(_summary(), "2026-Q1")
    assert "2026-Q1" in e.html


def test_html_contains_top_skills():
    e = build_quarterly_email(_summary(), "2026-Q1")
    assert "pdf-clause-extractor" in e.html
    assert "csv-data-summarizer" in e.html


def test_html_contains_net_savings():
    s = _summary(savings_eur=9.20, bibividi_share_eur=1.84)
    e = build_quarterly_email(s, "2026-Q1")
    # net = 9.20 - 1.84 = 7.36
    assert "7.36" in e.html


def test_html_contains_co2():
    e = build_quarterly_email(_summary(), "2026-Q1")
    # co2_grams = 30_000 → 30.00kg
    assert "30.00kg" in e.html or "kg" in e.html


def test_text_body_contains_key_fields():
    e = build_quarterly_email(_summary(), "2026-Q1")
    assert "Tokens saved" in e.text
    assert "CO\u2082" in e.text or "CO2" in e.text or "grams" in e.text
    assert "Gross savings" in e.text


def test_no_top_skills_graceful():
    s = _summary(top_skills=[])
    e = build_quarterly_email(s, "2026-Q1")
    assert "No skills" in e.html or "No skills" in e.text or e.html


def test_only_top_3_skills_shown():
    s = _summary(top_skills=[
        {"skill_id": f"skill-{i}", "uses": 100 - i}
        for i in range(10)
    ])
    e = build_quarterly_email(s, "2026-Q1")
    # Only first 3 in HTML
    assert "skill-0" in e.html
    assert "skill-1" in e.html
    assert "skill-2" in e.html
    assert "skill-9" not in e.html


# ── StatsTracker.quarterly_summary ────────────────────────────────────────────

@pytest.mark.asyncio
async def test_quarterly_summary_empty_db(tmp_path):
    from unittest.mock import patch

    from bvd.engine.stats import StatsTracker

    db = tmp_path / "test.db"
    with patch("bvd.config.settings.db_path", db):
        from bvd.engine.library import Library
        lib = Library()
        await lib.init()
        await lib.close()

        tracker = StatsTracker()
        result = await tracker.quarterly_summary(2026, 1)

    assert result["calls"] == 0
    assert result["tokens_saved"] == 0
    assert result["savings_eur"] == 0.0
    assert result["top_skills"] == []


@pytest.mark.asyncio
async def test_quarterly_summary_aggregates_3_months(tmp_path):
    from datetime import datetime
    from unittest.mock import patch

    import aiosqlite

    from bvd.engine.stats import StatsTracker

    db = tmp_path / "test.db"
    with patch("bvd.config.settings.db_path", db):
        from bvd.engine.library import Library
        lib = Library()
        await lib.init()
        await lib.close()

        async with aiosqlite.connect(db) as conn:
            await conn.execute(
                "INSERT INTO scripts (id, name, description, code, created_at, updated_at) "
                "VALUES (?, ?, ?, ?, ?, ?)",
                ("s1", "Test", "desc", "print('x')",
                 datetime.now(UTC).isoformat(),
                 datetime.now(UTC).isoformat()),
            )
            # Q1 = Jan, Feb, Mar — insert one execution each
            for month in (1, 2, 3):
                await conn.execute(
                    "INSERT INTO executions "
                    "(script_id, tokens_before, tokens_after, latency_ms, executed_at) "
                    "VALUES (?, ?, ?, ?, ?)",
                    ("s1", 10_000, 2_000, 50.0,
                     datetime(2026, month, 15, tzinfo=UTC).isoformat()),
                )
            # Q2 execution — should be excluded
            await conn.execute(
                "INSERT INTO executions "
                "(script_id, tokens_before, tokens_after, latency_ms, executed_at) "
                "VALUES (?, ?, ?, ?, ?)",
                ("s1", 50_000, 5_000, 50.0,
                 datetime(2026, 4, 1, tzinfo=UTC).isoformat()),
            )
            await conn.commit()

        tracker = StatsTracker()
        result = await tracker.quarterly_summary(2026, 1)

    # 3 months × 8000 tokens saved each = 24,000
    assert result["calls"] == 3
    assert result["tokens_saved"] == 24_000


@pytest.mark.asyncio
async def test_quarterly_summary_top_skills(tmp_path):
    from datetime import datetime
    from unittest.mock import patch

    import aiosqlite

    from bvd.engine.stats import StatsTracker

    db = tmp_path / "test.db"
    with patch("bvd.config.settings.db_path", db):
        from bvd.engine.library import Library
        lib = Library()
        await lib.init()
        await lib.close()

        async with aiosqlite.connect(db) as conn:
            for sid in ("skill-a", "skill-b", "skill-c"):
                await conn.execute(
                    "INSERT INTO scripts (id, name, description, code, created_at, updated_at) "
                    "VALUES (?, ?, ?, ?, ?, ?)",
                    (sid, sid, "desc", "",
                     datetime.now(UTC).isoformat(),
                     datetime.now(UTC).isoformat()),
                )
            # skill-a: 5 uses, skill-b: 3 uses, skill-c: 1 use
            for _ in range(5):
                await conn.execute(
                    "INSERT INTO executions "
                    "(script_id, tokens_before, tokens_after, latency_ms, executed_at) "
                    "VALUES (?, ?, ?, ?, ?)",
                    ("skill-a", 1000, 100, 10.0,
                     datetime(2026, 2, 1, tzinfo=UTC).isoformat()),
                )
            for _ in range(3):
                await conn.execute(
                    "INSERT INTO executions "
                    "(script_id, tokens_before, tokens_after, latency_ms, executed_at) "
                    "VALUES (?, ?, ?, ?, ?)",
                    ("skill-b", 1000, 100, 10.0,
                     datetime(2026, 2, 1, tzinfo=UTC).isoformat()),
                )
            await conn.execute(
                "INSERT INTO executions "
                "(script_id, tokens_before, tokens_after, latency_ms, executed_at) "
                "VALUES (?, ?, ?, ?, ?)",
                ("skill-c", 1000, 100, 10.0,
                 datetime(2026, 2, 1, tzinfo=UTC).isoformat()),
            )
            await conn.commit()

        tracker = StatsTracker()
        result = await tracker.quarterly_summary(2026, 1)

    skills = result["top_skills"]
    assert len(skills) <= 3
    assert skills[0]["skill_id"] == "skill-a"
    assert skills[0]["uses"] == 5
    assert skills[1]["skill_id"] == "skill-b"
