from __future__ import annotations

import sqlite3
import sys
import importlib.util
from types import SimpleNamespace
from datetime import date
from pathlib import Path

import pytest

ROOT = Path(__file__).resolve().parents[1]
HEALTH = ROOT / "scripts" / "health"
if str(HEALTH) not in sys.path:
    sys.path.insert(0, str(HEALTH))

from dashboard_v5.nutrition_contract import NUTRIENT_CONTRACTS, normalize_nutrient  # noqa: E402
from dashboard_v5.read_api import dispatch_api  # noqa: E402
from dashboard_v5.reference_contract import public_reference_context  # noqa: E402
from dashboard_v5.render import render  # noqa: E402
from dashboard_v5.data_provider import build_bundle, connect  # noqa: E402
from dashboard_v5.sprint6f_b_schema import assert_supplement_schema, apply_supplement_schema  # noqa: E402
from dashboard_v5.supplement_contract import validate_supplement_payload  # noqa: E402
_FIXTURE_PATH = ROOT / "tests" / "fixtures" / "dashboard_v5_fixture.py"
_loader = importlib.util.spec_from_file_location("sprint6f_b_fixture", _FIXTURE_PATH)
assert _loader and _loader.loader
_fixture = importlib.util.module_from_spec(_loader)
_loader.loader.exec_module(_fixture)
build_dashboard_v5_fixture = _fixture.build_dashboard_v5_fixture


@pytest.fixture()
def db(tmp_path: Path) -> Path:
    target = tmp_path / "fixture.db"
    build_dashboard_v5_fixture(target, anchor_date=date(2026, 6, 15))
    connection = sqlite3.connect(target)
    apply_supplement_schema(connection)
    connection.commit()
    assert_supplement_schema(connection)
    connection.close()
    return target


def test_three_reference_contexts_stay_separate() -> None:
    lab = public_reference_context(SimpleNamespace(source="laborwerte", parser_contract="lab"))
    personal = public_reference_context(SimpleNamespace(source="apple_health", parser_contract="apple"))
    nutrition = public_reference_context(SimpleNamespace(source="nutrition_daily_summary_v2", parser_contract="yazio"))
    assert [lab["type"], personal["type"], nutrition["type"]] == [
        "laboratory_reference",
        "personal_comparison",
        "nutrition_orientation",
    ]
    assert "Nicht dokumentiert" in lab["display_rule"]
    assert personal["label"] == "Persönlicher Vergleich"
    assert nutrition["range_status"] == "not_shown_without_complete_profile_and_value_contract"


def test_yazio_contract_expands_vitamins_and_minerals_fail_closed() -> None:
    assert NUTRIENT_CONTRACTS["vitamin.b12"].unit == "µg"
    assert NUTRIENT_CONTRACTS["mineral.calcium"].unit == "mg"
    assert normalize_nutrient("vitamin.b12", 2.5, None) is None
    assert normalize_nutrient("vitamin.b12", 2.5, "mg") is None


def test_supplement_plan_and_actual_are_strictly_separate() -> None:
    common = {
        "product": "Synthetisches Präparat", "brand_variant": "Test", "nutrient_key": "vitamin.b12",
        "amount": 2.5, "unit": "µg", "composition_source": "synthetisches Etikett",
        "assignment_reliability": "exact_label", "notes": "",
    }
    plan = validate_supplement_payload({"version": 1, "action": "supplement_plan", **common, "schedule_type": "regular", "weekdays": "mo,we", "interval_days": None, "start_date": "2026-06-01", "end_date": None})
    actual = validate_supplement_payload({"version": 1, "action": "supplement_intake", **common, "status": "administered", "occurred_at": "2026-06-15T08:00:00+02:00", "plan_id": None})
    assert "occurred_at" not in plan
    assert "schedule_type" not in actual
    with pytest.raises(ValueError):
        validate_supplement_payload({**plan, "occurred_at": "2026-06-15T08:00:00+02:00"})


def test_supplement_api_and_nutrition_total_keep_yazio_primary(db: Path) -> None:
    connection = sqlite3.connect(db)
    item_id = connection.execute("SELECT id FROM nutrition_items WHERE datum=? ORDER BY id LIMIT 1", ("2026-06-14",)).fetchone()[0]
    connection.execute(
        "INSERT OR REPLACE INTO nutrition_item_nutrients(item_id,nutrient_key,value,unit) VALUES(?,?,?,?)",
        (item_id, "nutrient.dietaryfiber", 5.0, "g"),
    )
    connection.execute(
        """INSERT INTO supplement_intakes
        (product,brand_variant,nutrient_key,amount,unit,status,occurred_at,composition_source,assignment_reliability,notes,created_at)
        VALUES(?,?,?,?,?,?,?,?,?,?,?)""",
        ("Synthetisches Präparat", "Test", "nutrient.dietaryfiber", 3.0, "g", "administered", "2026-06-14T08:00:00+02:00", "synthetisches Etikett", "exact_label", None, "2026-06-14T08:01:00+02:00"),
    )
    connection.commit()
    connection.close()
    supplements = dispatch_api(db, "/api/v1/supplements", "from=2026-06-14&to=2026-06-14")
    assert len(supplements["administered"]) == 1
    day = dispatch_api(db, "/api/v1/nutrition/day/2026-06-14", "")
    nutrient = day["nutrients"]["nutrient.dietaryfiber"]
    assert nutrient["food_source"] == "YAZIO"
    assert nutrient["total_value"] == pytest.approx(nutrient["food_value"] + 3.0)
    assert nutrient["supplement_value"] == 3.0


def test_nutrition_average_contract_is_explicit(db: Path) -> None:
    data = dispatch_api(db, "/api/v1/nutrition/days", "from=2026-06-10&to=2026-06-14")
    assert "kein validierter Entzündungsindex" in data["nutrition_factor_statement"]
    factor = data["nutrition_factors"][0]
    assert factor["aggregation"] == "arithmetic_mean_per_documented_day"
    assert factor["period"] == {"from": "2026-06-10", "to": "2026-06-14"}
    assert factor["expected_days"] == 5
    assert "median" in factor


def test_series_carries_versioned_reference_context(db: Path) -> None:
    payload = dispatch_api(db, "/api/v1/series", "metric=apple.hrv&resolution=day&from=2026-06-10&to=2026-06-15")
    assert payload["reference_context"]["type"] == "personal_comparison"
    assert payload["reference_context"]["label"] == "Persönlicher Vergleich"


def test_render_contains_panel_metadata_supplements_and_report_charts(db: Path) -> None:
    connection = connect(db)
    try:
        bundle = build_bundle(connection, today="2026-06-15")
    finally:
        connection.close()
    html = render(bundle, health_record_6e=True)
    for text in (
        "Ernährungsfaktoren im gewählten Zeitraum",
        "Durchschnitt pro dokumentiertem Tag im gewählten Zeitraum",
        "Supplement dokumentieren",
        "Datenaufbereitung",
    ):
        assert text in html
    assert "Entzündungsrelevante Ernährungsfaktoren" not in html
    record_js = (ROOT / "scripts/health/assets/health-assets/dashboard-v5-record.js").read_text()
    assert "Grafiken auswählen und sortieren (maximal vier)" in record_js
    assert "doctor-summary-echart" in record_js


def test_forbidden_medical_claims_absent_from_changed_ui() -> None:
    text = "\n".join((ROOT / path).read_text() for path in (
        "scripts/health/assets/health-assets/dashboard-v5-nutrition.js",
        "scripts/health/assets/health-assets/dashboard-v5-record.js",
        "scripts/health/dashboard_v5/reference_contract.py",
    ))
    for forbidden in ("Du hast einen Mangel", "Du brauchst Supplement", "Nimm täglich", "verursacht einen Schub"):
        assert forbidden not in text
