"""
BIBIVIDI — CSRD Reports tests (TODO-14)
Tests for bvd/reports.py: build_csrd_report(), to_csv(), to_html().
"""
from __future__ import annotations

from datetime import UTC

import pytest

from bvd.reports import (
    CO2_FACTOR_G_PER_TOKEN,
    CsrdMonthlyReport,
    build_csrd_report,
    to_csv,
    to_html,
)

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

def _make_report(**overrides) -> CsrdMonthlyReport:
    defaults = dict(
        year=2026, month=3,
        executions=100,
        tokens_in=1_000_000,
        tokens_saved=750_000,
        saving_ratio=0.75,
        co2_factor_g_per_token=CO2_FACTOR_G_PER_TOKEN,
        co2_baseline_g=3000.0,
        co2_saved_g=2250.0,
        co2_net_g=750.0,
        savings_eur=0.6900,
        generated_at="2026-03-31T23:59:59+00:00",
        methodology="Test methodology",
        disclaimer="Test disclaimer",
    )
    defaults.update(overrides)
    return CsrdMonthlyReport(**defaults)


# ── CsrdMonthlyReport properties ──────────────────────────────────────────────

def test_period_label():
    r = _make_report(year=2026, month=3)
    assert r.period_label == "2026-03"


def test_co2_saved_kg():
    r = _make_report(co2_saved_g=2250.0)
    assert r.co2_saved_kg == 2.25


def test_co2_saved_kg_small():
    r = _make_report(co2_saved_g=500.0)
    assert r.co2_saved_kg == 0.5


# ── to_csv ────────────────────────────────────────────────────────────────────

def test_csv_contains_header():
    r = _make_report()
    csv_str = to_csv(r)
    assert "BIBIVIDI CSRD" in csv_str
    assert "2026-03" in csv_str


def test_csv_contains_key_metrics():
    r = _make_report(tokens_saved=750_000, co2_saved_g=2250.0)
    csv_str = to_csv(r)
    assert "750000" in csv_str
    assert "2250.000" in csv_str


def test_csv_contains_methodology():
    r = _make_report()
    csv_str = to_csv(r)
    assert "Test methodology" in csv_str


def test_csv_contains_disclaimer():
    r = _make_report()
    csv_str = to_csv(r)
    assert "Test disclaimer" in csv_str


def test_csv_semicolon_delimiter():
    r = _make_report()
    csv_str = to_csv(r)
    # Semicolon-delimited (CSRD-compatible European format)
    assert ";" in csv_str


def test_csv_has_unit_column():
    r = _make_report()
    csv_str = to_csv(r)
    assert "gCO₂eq" in csv_str or "kgCO" in csv_str


# ── to_html ───────────────────────────────────────────────────────────────────

def test_html_is_valid_document():
    r = _make_report()
    html = to_html(r)
    assert "<!DOCTYPE html>" in html
    assert "<html" in html
    assert "</html>" in html


def test_html_contains_period():
    r = _make_report(year=2026, month=3)
    html = to_html(r)
    assert "2026-03" in html


def test_html_contains_co2_saved():
    r = _make_report(co2_saved_g=2250.0)
    html = to_html(r)
    # 2250g → 2.250 kg
    assert "2.250 kgCO" in html


def test_html_contains_reduction_ratio():
    r = _make_report(saving_ratio=0.75)
    html = to_html(r)
    assert "75.0%" in html


def test_html_contains_methodology():
    r = _make_report()
    html = to_html(r)
    assert "Test methodology" in html


def test_html_contains_disclaimer():
    r = _make_report()
    html = to_html(r)
    assert "Test disclaimer" in html


def test_html_large_co2_shown_in_tonnes():
    # 1_500_000 g → 1.500 tCO₂eq
    r = _make_report(co2_saved_g=1_500_000.0)
    html = to_html(r)
    assert "1.500 tCO" in html


# ── build_csrd_report ──────────────────────────────────────────────────────────

@pytest.mark.asyncio
async def test_build_csrd_report_empty_db(tmp_path):
    """Empty DB returns a zero report with correct metadata."""
    from unittest.mock import patch

    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()

        r = await build_csrd_report(2026, 3)

    assert r.year == 2026
    assert r.month == 3
    assert r.executions == 0
    assert r.tokens_in == 0
    assert r.tokens_saved == 0
    assert r.co2_saved_g == 0.0
    assert r.co2_baseline_g == 0.0
    assert r.co2_net_g == 0.0
    assert r.period_label == "2026-03"


@pytest.mark.asyncio
async def test_build_csrd_report_with_executions(tmp_path):
    """CO₂ figures computed correctly from real executions."""
    from datetime import datetime
    from unittest.mock import patch

    import aiosqlite

    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()),
            )
            # 100,000 tokens before → 20,000 after → 80,000 saved
            await conn.execute(
                "INSERT INTO executions "
                "(script_id, tokens_before, tokens_after, latency_ms, executed_at) "
                "VALUES (?, ?, ?, ?, ?)",
                ("s1", 100_000, 20_000, 100.0,
                 datetime(2026, 3, 15, tzinfo=UTC).isoformat()),
            )
            await conn.commit()

        r = await build_csrd_report(2026, 3)

    assert r.executions == 1
    assert r.tokens_in == 100_000
    assert r.tokens_saved == 80_000
    assert r.saving_ratio == 0.8
    # CO₂: 80,000 × 0.003 = 240 gCO₂eq
    assert abs(r.co2_saved_g - 240.0) < 0.001
    # Baseline: 100,000 × 0.003 = 300 gCO₂eq
    assert abs(r.co2_baseline_g - 300.0) < 0.001
    assert abs(r.co2_net_g - 60.0) < 0.001


@pytest.mark.asyncio
async def test_build_csrd_report_filters_by_month(tmp_path):
    """Only executions in the target month are included."""
    from datetime import datetime
    from unittest.mock import patch

    import aiosqlite

    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()),
            )
            for month, tokens_before, tokens_after in [
                (3, 50_000, 10_000),   # target: 40K saved
                (2, 200_000, 10_000),  # excluded
                (4, 300_000, 10_000),  # excluded
            ]:
                await conn.execute(
                    "INSERT INTO executions "
                    "(script_id, tokens_before, tokens_after, latency_ms, executed_at) "
                    "VALUES (?, ?, ?, ?, ?)",
                    ("s1", tokens_before, tokens_after, 50.0,
                     datetime(2026, month, 15, tzinfo=UTC).isoformat()),
                )
            await conn.commit()

        r = await build_csrd_report(2026, 3)

    assert r.tokens_saved == 40_000   # only March
    assert r.executions == 1


@pytest.mark.asyncio
async def test_build_csrd_report_generated_at_is_iso8601(tmp_path):
    """generated_at is a valid ISO-8601 timestamp."""
    from datetime import datetime
    from unittest.mock import patch

    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()

        r = await build_csrd_report(2026, 3)

    # Should not raise
    parsed = datetime.fromisoformat(r.generated_at.replace("Z", "+00:00"))
    assert parsed.year >= 2026
