"""Sprint-6B Metric Catalog v2 source and search contracts."""
from __future__ import annotations

import sqlite3
import sys
from dataclasses import fields
from pathlib import Path

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.metric_catalog_v2 import (  # noqa: E402
    APPLE_SOURCE_SPECS,
    BY_ID_V2,
    LAB_CATALOG_SPECS,
    MetricV2,
    catalog_search,
    inventory_sources,
    public_catalog,
)
from dashboard_v5.data_provider import APPLE_SPECS as SNAPSHOT_APPLE_SPECS  # noqa: E402

REQUIRED_FIELDS = {
    "id", "label", "aliases", "category", "source", "unit", "value_type",
    "precision", "aggregation", "expected_frequency", "overlay_group",
    "baseline_rule", "reference_policy", "search_terms", "drill_down_target",
    "correlation_enabled", "allowed_lags", "privacy_class",
}


def inventory_db() -> sqlite3.Connection:
    connection = sqlite3.connect(":memory:")
    connection.row_factory = sqlite3.Row
    connection.executescript(
        """
        CREATE TABLE apple_health_records(
            metric TEXT, unit TEXT, value REAL, raw_json TEXT, start_date TEXT
        );
        CREATE TABLE laborwerte(
            parameter_name TEXT, einheit TEXT, validierungsstatus TEXT,
            verified_against_original INTEGER, reference_range_source TEXT,
            wert TEXT, abnahme_datum TEXT, befund_datum TEXT,
            reference_min TEXT, reference_max TEXT
        );
        CREATE TABLE vitalzeichen(parameter TEXT, einheit TEXT, wert TEXT);
        """
    )
    connection.executemany(
        """INSERT INTO apple_health_records(metric,unit,value,raw_json,start_date)
           VALUES(?,?,?,?,?)""",
        [
            ("sleep_analysis", "hr", 7.0, None, "2026-06-15T12:00:00+02:00"),
            ("resting_heart_rate", "count/min", 60.0, None, "2026-06-15T12:00:00+02:00"),
            ("heart_rate_variability", "ms", 42.0, None, "2026-06-15T12:00:00+02:00"),
            ("step_count", "count", 0.0, None, "2026-06-15T12:00:00+02:00"),
            ("walking_running_distance", "km", 3.2, None, "2026-06-15T12:00:00+02:00"),
            ("active_energy", "kJ", 500.0, None, "2026-06-15T12:00:00+02:00"),
            ("blood_oxygen_saturation", "%", 98.0, None, "2026-06-15T12:00:00+02:00"),
            ("respiratory_rate", "count/min", 14.0, None, "2026-06-15T12:00:00+02:00"),
            ("physical_effort", "kcal/hr·kg", 2.0, None, "2026-06-15T12:00:00+02:00"),
            ("weight_body_mass", "kg", 70.0, None, "2026-06-15T12:00:00+02:00"),
            ("body_mass_index", "count", 22.0, None, "2026-06-15T12:00:00+02:00"),
            ("blood_pressure", "mmHg", None, '{"systolic":120,"diastolic":80}', "2026-06-15T12:00:00+02:00"),
            ("unreleased_synthetic_metric", "widgets", 1.0, None, "2026-06-15T12:00:00+02:00"),
        ],
    )
    connection.executemany(
        "INSERT INTO laborwerte VALUES(?,?,?,?,?,?,?,?,?,?)",
        [
            ("C-Reaktives Protein (CRP)", "mg/l", "validiert", 1, "scanned_original", "1.2", "2026-06-15", None, "0", "5"),
            ("Unreviewed Wish Metric", "x", "validiert", 0, "unknown", "1", "2026-06-15", None, None, None),
        ],
    )
    connection.execute("INSERT INTO vitalzeichen VALUES('Blutdruck','mmHg','120/80')")
    return connection


def test_catalog_v2_has_complete_stable_contract_and_source_evidence():
    assert REQUIRED_FIELDS <= {item.name for item in fields(MetricV2)}
    catalog = public_catalog()
    assert len(catalog) == len({item["id"] for item in catalog})
    assert all(REQUIRED_FIELDS <= set(item) for item in catalog)
    assert all(item["privacy_class"] == "health_sensitive" for item in catalog)
    assert all(item["source_identifier"] and item["parser_contract"] for item in catalog)
    assert all(item["aggregation"] in {"sum", "avg", "last", "panel", "observation"} for item in catalog)
    assert all(item["allowed_lags"] == sorted(set(item["allowed_lags"])) for item in catalog)
    assert set(APPLE_SOURCE_SPECS) >= {
        "sleep_analysis", "resting_heart_rate", "heart_rate_variability", "step_count",
        "walking_running_distance", "active_energy", "blood_oxygen_saturation",
        "respiratory_rate", "physical_effort", "weight_body_mass", "body_mass_index",
        "blood_pressure",
    }
    assert set(LAB_CATALOG_SPECS) == {"CRP", "D-Dimer", "Fibrinogen", "Faktor VIII", "Thrombozyten", "Leukozyten", "Ferritin"}
    for identifier, spec in APPLE_SOURCE_SPECS.items():
        for metric_id in spec.metric_ids:
            metric = BY_ID_V2[metric_id]
            assert metric.source_identifier == identifier
            assert metric.parser_contract == spec.parser_contract
            if metric.value_type != "panel":
                assert metric.aggregation == spec.aggregation
    for parameter, spec in LAB_CATALOG_SPECS.items():
        metric = BY_ID_V2[spec.metric_id]
        assert metric.source_identifier == parameter
        assert metric.unit == spec.unit
        assert metric.reference_policy == "observation_specific_verified_original"


def test_blood_pressure_is_a_panel_with_two_components_and_required_aliases():
    panel = BY_ID_V2["panel.blood_pressure"]
    systolic = BY_ID_V2["apple.blood_pressure.systolic"]
    diastolic = BY_ID_V2["apple.blood_pressure.diastolic"]
    assert panel.value_type == "panel"
    assert panel.reference_policy == "paired_panel"
    assert systolic.panel_id == panel.id == diastolic.panel_id
    assert systolic.unit == diastolic.unit == "mmHg"
    terms = {term.casefold() for metric in (panel, systolic, diastolic) for term in (*metric.aliases, *metric.search_terms)}
    assert {"blutdruck", "bd", "rr", "systolisch", "diastolisch"} <= terms


def test_inventory_is_programmatic_and_never_auto_releases_unknown_identifiers():
    connection = inventory_db()
    try:
        inventory = inventory_sources(connection)
    finally:
        connection.close()
    apple = {item["identifier"]: item for item in inventory["apple_health"]}
    assert apple["step_count"]["numeric_observations"] == 1
    assert apple["step_count"]["released_metric_ids"] == ["apple.steps"]
    assert apple["unreleased_synthetic_metric"]["released_metric_ids"] == []
    assert apple["unreleased_synthetic_metric"]["status"] == "observed_not_released"
    assert inventory["vital_signs"] == [{
        "identifier": "Blutdruck", "units": ["mmHg"], "observations": 1,
        "released_metric_ids": [], "status": "observed_not_released",
    }]
    assert inventory["laboratory"][0]["canonical_parameter"] == "CRP"
    assert inventory["laboratory"][0]["status"] == "verified_canonical"


def test_alias_search_is_grouped_deterministic_and_reports_supported_without_data():
    connection = inventory_db()
    try:
        pressure = catalog_search(connection, "Blutdruck")
        pulse = catalog_search(connection, "Puls")
        aphthae = catalog_search(connection, "Aphten")
    finally:
        connection.close()
    assert [item["id"] for item in pressure[:3]] == [
        "panel.blood_pressure", "apple.blood_pressure.systolic", "apple.blood_pressure.diastolic",
    ]
    assert all(item["availability"]["status"] in {"available", "supported_no_data"} for item in pressure[:3])
    assert any(item["id"] == "apple.resting_heart_rate" for item in pulse)
    assert any(item["id"] == "symptom.aphthae" for item in aphthae)
    assert catalog_search(connection, "x") == []

    empty_pressure = inventory_db()
    try:
        empty_pressure.execute("DELETE FROM apple_health_records WHERE metric='blood_pressure'")
        empty_pressure.commit()
        no_data = catalog_search(empty_pressure, "Blutdruck")
        fibrinogen = catalog_search(empty_pressure, "Fibrinogen")
    finally:
        empty_pressure.close()
    assert [item["availability"]["status"] for item in no_data[:3]] == [
        "supported_no_data", "supported_no_data", "supported_no_data",
    ]
    assert fibrinogen[0]["availability"]["status"] == "supported_no_data"


def test_static_snapshot_remains_the_small_print_fallback_not_the_large_api_catalog():
    assert set(SNAPSHOT_APPLE_SPECS) == {
        "apple.sleep", "apple.resting_heart_rate", "apple.hrv", "apple.steps",
    }
    source = (HEALTH / "dashboard_v5/data_provider.py").read_text(encoding="utf-8")
    assert "metric_catalog_v2" not in source
    assert "read_api" not in source


def test_availability_requires_releasable_unit_value_date_and_covers_nutrition():
    connection = inventory_db()
    try:
        connection.execute(
            "UPDATE apple_health_records SET unit='widgets' WHERE metric='step_count'"
        )
        connection.execute(
            """UPDATE laborwerte SET wert='NOT A NUMBER',abnahme_datum=NULL,befund_datum=NULL
               WHERE parameter_name='C-Reaktives Protein (CRP)'"""
        )
        connection.execute(
            """CREATE TABLE nutrition_daily_summary_v2(
                   datum TEXT,histamine_score REAL,item_count INTEGER,
                   histamine_unknown_count INTEGER,histamine_label TEXT
               )"""
        )
        connection.execute(
            "INSERT INTO nutrition_daily_summary_v2 VALUES('2026-06-15',0,1,0,'green')"
        )
        connection.commit()
        steps = catalog_search(connection, "Schritte")[0]
        connection.execute(
            """UPDATE apple_health_records
               SET unit='count',start_date='2099-01-02T12:00:00+01:00'
               WHERE metric='step_count'"""
        )
        future_steps = catalog_search(connection, "Schritte")[0]
        crp = catalog_search(connection, "CRP")[0]
        histamine = catalog_search(connection, "Histamin")[0]
    finally:
        connection.close()
    assert steps["availability"] == {"status": "supported_no_data", "observations": 0}
    assert future_steps["availability"] == {"status": "supported_no_data", "observations": 0}
    assert crp["availability"] == {"status": "supported_no_data", "observations": 0}
    assert histamine["availability"] == {"status": "available", "observations": 1}
