from __future__ import annotations

import hashlib
import json
import sqlite3
import sys
from datetime import date
from pathlib import Path

import pytest

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

from dashboard_v5.capture_contract import validate_capture_payload
from dashboard_v5.medication_contract import MedicationFieldError, resolve_action_preview
from dashboard_v5.medication_schema import apply_schema, assert_schema
from dashboard_v5.read_api import dispatch_api
from fixtures.dashboard_v5_fixture import build_dashboard_v5_fixture
import health_dashboard_action_worker as worker


def _case(tmp_path: Path):
    database = tmp_path / "health.db"
    build_dashboard_v5_fixture(database, anchor_date=date(2026, 8, 22))
    api = dispatch_api(database, "/api/v1/medications", "")
    rx = next(item for item in api["prescriptions"] if item["name"] == "Hyrimoz / Adalimumab")
    return database, api, rx


def _payload(rx: dict, **overrides):
    data = {
        "contract": "health.medication_action.v2",
        "mode": "historical",
        "status": "administered",
        "medication_ref": rx["id"],
        "planned_event_ref": "",
        "name": rx["name"],
        "quantity_value": "1",
        "dosage_form": "Spritze",
        "strength": "40 mg/0,4 ml",
        "route_original": "subkutan",
        "route_normalized": "subcutaneous",
        "injection_region": "Oberschenkel",
        "injection_side": "right",
        "injection_detail": "rechtes Bein",
        "note": "Spritze wie üblich.",
        "preset_revision": rx["administration_preset"]["preset_revision"],
        "preview_revision": "",
        "deviation_confirmed": False,
        "duplicate_confirmed": False,
    }
    data.update(overrides.pop("data", {}))
    payload = {
        "version": 1,
        "action": "capture_entry",
        "capture_type": "medication",
        "request_version": 1,
        "idempotency_key": "0123456789abcdef0123456789abcdef",
        "occurred_at": "2026-08-17T12:32",
        "ended_at": None,
        "data": data,
        "attachments": [],
        "corrects_entry_id": None,
        "withdraws_entry_id": None,
    }
    payload.update(overrides)
    return payload


def test_f1_schema_and_hyrimoz_preset_are_additive_and_idempotent(tmp_path: Path) -> None:
    database, _, rx = _case(tmp_path)
    connection = sqlite3.connect(database)
    connection.row_factory = sqlite3.Row
    assert apply_schema(connection) == []
    assert_schema(connection)
    assert rx["status"] == "unknown"
    assert rx["administration_preset"] == {
        "quantity_value": "1",
        "dosage_form": "Spritze",
        "strength": "40 mg/0,4 ml",
        "route_original": "subkutan",
        "route_normalized": "subcutaneous",
        "preset_revision": rx["administration_preset"]["preset_revision"],
    }
    assert connection.execute("PRAGMA integrity_check").fetchone()[0] == "ok"
    assert connection.execute("PRAGMA foreign_key_check").fetchall() == []
    connection.execute("INSERT INTO medikamente(medikament_name,anwendungsform) VALUES('Hyrimoz / Adalimumab','subkutan')")
    connection.commit()
    with pytest.raises(RuntimeError, match="identity is ambiguous"):
        apply_schema(connection)


def test_exact_unknown_status_historical_hyrimoz_capture_and_replay(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
    database, _, rx = _case(tmp_path)
    payload = validate_capture_payload(_payload(rx))
    connection = sqlite3.connect(database)
    connection.row_factory = sqlite3.Row
    revision, prescription, planned, target = resolve_action_preview(connection, payload)
    assert prescription["prescription_status"] == "unknown"
    assert planned is target is None
    payload["data"]["preview_revision"] = revision
    before = connection.execute("SELECT count(*) FROM medication_administrations").fetchone()[0]
    medication_id = connection.execute("SELECT id FROM medikamente WHERE medikament_name='Hyrimoz / Adalimumab'").fetchone()[0]
    with pytest.raises(sqlite3.IntegrityError, match="structured medication fields"):
        connection.execute(
            """INSERT INTO medication_administrations(
                   datum,medication_name,event_type,source,occurred_at,medication_id,business_revision)
                 VALUES('2026-08-17','Hyrimoz / Adalimumab','administered',
                        'dashboard_medication_action_version_two','2026-08-17T12:32',?,?)""",
            (medication_id, "a" * 64),
        )
    connection.close()

    action_dir = tmp_path / "actions"
    media_dir = tmp_path / "media"
    quarantine_dir = tmp_path / "quarantine"
    for path in (action_dir, media_dir, quarantine_dir):
        path.mkdir(mode=0o700)
    monkeypatch.setattr(worker, "DASHBOARD_DB", database)
    monkeypatch.setattr(worker, "ACTION_INBOX", action_dir)
    monkeypatch.setattr(worker, "CAPTURE_MEDIA", media_dir)
    monkeypatch.setattr(worker, "CAPTURE_QUARANTINE", quarantine_dir)
    first = worker.apply_capture_action(payload)
    second = worker.apply_capture_action(payload)
    assert first == second
    action_hash = hashlib.sha256(worker._canonical_json(payload).encode()).hexdigest()
    worker.write_capture_receipt(payload["idempotency_key"], "processed", action_hash)
    receipt = json.loads((action_dir / "capture-receipts" / f"{payload['idempotency_key']}.json").read_text())
    assert receipt == {
        "version": 2, "status": "processed", "action_hash": action_hash,
        "processed_at": receipt["processed_at"],
    }

    connection = sqlite3.connect(database)
    connection.row_factory = sqlite3.Row
    rows = connection.execute(
        """SELECT occurred_at,actual_quantity_value,actual_dosage_form,actual_strength,
                  route_normalized,injection_region,injection_side,injection_detail,notes
             FROM medication_administrations
            WHERE source='dashboard_medication_action_version_two'"""
    ).fetchall()
    assert connection.execute("SELECT count(*) FROM medication_administrations").fetchone()[0] == before + 1
    assert len(rows) == 1
    assert dict(rows[0]) == {
        "occurred_at": "2026-08-17T12:32",
        "actual_quantity_value": "1",
        "actual_dosage_form": "Spritze",
        "actual_strength": "40 mg/0,4 ml",
        "route_normalized": "subcutaneous",
        "injection_region": "Oberschenkel",
        "injection_side": "right",
        "injection_detail": "rechtes Bein",
        "notes": "Spritze wie üblich.",
    }
    status = connection.execute(
        "SELECT prescription_status FROM medikamente WHERE medikament_name='Hyrimoz / Adalimumab'"
    ).fetchone()[0]
    assert status == "unknown"
    day = dispatch_api(database, "/api/v1/day/2026-08-17", "")
    assert day["medications"]["administered"] == [{
        "name": "Hyrimoz / Adalimumab", "dose": "1 Spritze · 40 mg/0,4 ml",
        "route": "subkutan", "note": "Spritze wie üblich.",
        "source": "dashboard_medication_action_version_two",
    }]
    calendar = dispatch_api(database, "/api/v1/calendar", "from=2026-08-17&to=2026-08-17")
    assert calendar["days"][0]["counts"]["medications"] >= 1
    assert "has_medications" in calendar["days"][0]["codes"]
    report = dispatch_api(
        database, "/api/v1/doctor-report",
        "from=2026-08-17&to=2026-08-17&sections=medications",
    )
    assert len(report["medications"]["administered"]) == 1
    assert report["medications"]["administered"][0]["actual_strength"] == "40 mg/0,4 ml"


def test_preset_match_needs_no_deviation_but_actual_deviation_does(tmp_path: Path) -> None:
    database, _, rx = _case(tmp_path)
    matching = validate_capture_payload(_payload(rx))
    connection = sqlite3.connect(database)
    connection.row_factory = sqlite3.Row
    assert resolve_action_preview(connection, matching)[0]
    changed = validate_capture_payload(_payload(rx, data={"strength": "80 mg/0,8 ml"}))
    with pytest.raises(RuntimeError, match="differs from verified preset"):
        resolve_action_preview(connection, changed)
    confirmed = validate_capture_payload(_payload(rx, data={"strength": "80 mg/0,8 ml", "deviation_confirmed": True}))
    assert resolve_action_preview(connection, confirmed)[0]
    route_changed = validate_capture_payload(_payload(rx, data={"route_original": "s.c."}))
    with pytest.raises(RuntimeError, match="differs from verified preset"):
        resolve_action_preview(connection, route_changed)
    connection.execute(
        "UPDATE medikamente SET administration_preset_strength='80 mg/0,8 ml' WHERE medikament_name='Hyrimoz / Adalimumab'"
    )
    connection.commit()
    with pytest.raises(RuntimeError, match="preset is no longer available"):
        resolve_action_preview(connection, matching)
    with pytest.raises(MedicationFieldError) as invalid:
        validate_capture_payload(_payload(rx, data={"strength": "/home/private"}))
    assert invalid.value.field == "strength"
    with pytest.raises(MedicationFieldError) as invalid_quantity:
        validate_capture_payload(_payload(rx, data={"quantity_value": "1 Spritze"}))
    assert invalid_quantity.value.field == "quantity_value"


def test_structured_correction_is_append_only_idempotent_and_effective_once(
    tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
    database, _, rx = _case(tmp_path)
    connection = sqlite3.connect(database)
    connection.row_factory = sqlite3.Row
    selected_id = connection.execute(
        """SELECT id FROM medikamente
            WHERE medikament_name=? AND administration_preset_revision IS NOT NULL""",
        (rx["name"],),
    ).fetchone()[0]
    preset_columns = (
        "administration_preset_quantity_value=NULL,administration_preset_dosage_form=NULL,"
        "administration_preset_strength=NULL,administration_preset_route_original=NULL,"
        "administration_preset_route=NULL,administration_preset_source=NULL,"
        "administration_preset_provenance=NULL,administration_preset_revision=NULL"
    )
    connection.execute(f"UPDATE medikamente SET {preset_columns} WHERE id=?", (selected_id,))
    connection.execute(
        "INSERT INTO medikamente(medikament_name,anwendungsform,business_revision) VALUES(?,?,?)",
        ("Hyrimoz / Adalimumab", "subkutan", "f" * 64),
    )
    duplicate_id = connection.execute("SELECT last_insert_rowid()").fetchone()[0]
    connection.commit()
    connection.close()

    for name in ("actions", "media", "quarantine"):
        (tmp_path / name).mkdir(mode=0o700)
    monkeypatch.setattr(worker, "DASHBOARD_DB", database)
    monkeypatch.setattr(worker, "ACTION_INBOX", tmp_path / "actions")
    monkeypatch.setattr(worker, "CAPTURE_MEDIA", tmp_path / "media")
    monkeypatch.setattr(worker, "CAPTURE_QUARANTINE", tmp_path / "quarantine")

    original = validate_capture_payload(
        _payload(
            rx,
            data={
                "strength": "40 mg", "route_original": "", "injection_region": "",
                "injection_detail": "Rechtes Bein", "note": "", "preset_revision": "",
            },
        )
    )
    connection = sqlite3.connect(database); connection.row_factory = sqlite3.Row
    original["data"]["preview_revision"] = resolve_action_preview(connection, original)[0]
    connection.close()
    original_entry = worker.apply_capture_action(original)

    api = dispatch_api(database, "/api/v1/medications", "from=2026-08-17&to=2026-08-17")
    target = next(item for item in api["administered"] if item["name"] == rx["name"])
    assert target["capture_entry_ref"] == original_entry
    baseline = target["correction_administration_preset"]
    assert baseline["bind_verified_preset"] is True
    correction = validate_capture_payload(
        _payload(
            rx,
            idempotency_key="fedcba9876543210fedcba9876543210",
            corrects_entry_id=original_entry,
            data={
                "mode": "correction", "status": "corrected", "quantity_value": "1",
                "dosage_form": "Spritze", "strength": "40 mg/0,4 ml",
                "route_original": "", "route_normalized": "subcutaneous",
                "injection_region": "", "injection_side": "right",
                "injection_detail": "Rechtes Bein", "note": "",
                "preset_revision": baseline["preset_revision"],
                "correction_target_ref": target["id"],
                "correction_reason": "Strukturierte Menge und vollständige Stärke berichtigt.",
                "bind_verified_preset": True, "deviation_confirmed": True,
            },
        )
    )
    connection = sqlite3.connect(database); connection.row_factory = sqlite3.Row
    revision, resolved_rx, planned, resolved_target = resolve_action_preview(connection, correction)
    assert planned is None and int(resolved_rx["id"]) == selected_id
    assert int(resolved_target["id"]) > 0
    correction["data"]["preview_revision"] = revision
    connection.close()

    corrected_entry = worker.apply_capture_action(correction)
    assert worker.apply_capture_action(correction) == corrected_entry

    connection = sqlite3.connect(database); connection.row_factory = sqlite3.Row
    rows = connection.execute(
        """SELECT event_type,actual_quantity_value,actual_dosage_form,actual_strength,
                  route_original,route_normalized,injection_region,injection_side,injection_detail,
                  corrects_event_id,corrected_target_status
             FROM medication_administrations
            WHERE source='dashboard_medication_action_version_two' ORDER BY id"""
    ).fetchall()
    assert [row["event_type"] for row in rows] == ["administered", "corrected"]
    assert tuple(rows[0][1:5]) == ("1", "Spritze", "40 mg", None)
    assert tuple(rows[1][1:9]) == (
        "1", "Spritze", "40 mg/0,4 ml", None, "subcutaneous", None, "right", "Rechtes Bein"
    )
    assert rows[1]["corrects_event_id"] is not None
    assert rows[1]["corrected_target_status"] == "administered"
    assert connection.execute(
        "SELECT administration_preset_strength FROM medikamente WHERE id=?", (selected_id,)
    ).fetchone()[0] == "40 mg/0,4 ml"
    assert connection.execute(
        "SELECT administration_preset_strength FROM medikamente WHERE id=?", (duplicate_id,)
    ).fetchone()[0] is None
    assert connection.execute("PRAGMA integrity_check").fetchone()[0] == "ok"
    assert connection.execute("PRAGMA foreign_key_check").fetchall() == []
    connection.close()

    api = dispatch_api(database, "/api/v1/medications", "from=2026-08-17&to=2026-08-17")
    administered_history = [item for item in api["administered"] if item["name"] == rx["name"]]
    corrected_history = [item for item in api["corrected"] if item["name"] == rx["name"]]
    assert len(administered_history) == len(corrected_history) == 1
    assert administered_history[0]["superseded_by_correction"] is True
    effective = corrected_history[0]
    assert effective["status"] == "corrected" and effective["effective_status"] == "administered"
    assert effective["route_original"] == ""
    assert (effective["actual_quantity_value"], effective["actual_dosage_form"], effective["actual_strength"]) == ("1", "Spritze", "40 mg/0,4 ml")
    day = dispatch_api(database, "/api/v1/day/2026-08-17", "")
    day_rows = [item for item in day["medications"]["administered"] if item["name"] == rx["name"]]
    assert len(day_rows) == 1 and day_rows[0]["dose"] == "1 Spritze · 40 mg/0,4 ml"
    events = dispatch_api(database, "/api/v1/events", "from=2026-08-17&to=2026-08-17&types=medication,medication_administered")
    assert len([item for item in events["events"] if item["label"] == rx["name"]]) == 1
    report = dispatch_api(database, "/api/v1/doctor-report", "from=2026-08-17&to=2026-08-17&sections=medications")
    report_rows = [item for item in report["medications"]["administered"] if item["name"] == rx["name"]]
    assert len(report_rows) == 1
    assert report["medications"]["corrected"] == []
    assert report_rows[0]["is_correction"] is True
    assert (
        report_rows[0]["actual_quantity_value"],
        report_rows[0]["actual_dosage_form"],
        report_rows[0]["actual_strength"],
    ) == ("1", "Spritze", "40 mg/0,4 ml")


def test_historical_and_real_plan_modes_are_fail_closed(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
    database, _, rx = _case(tmp_path)
    historical = validate_capture_payload(_payload(rx))
    connection = sqlite3.connect(database)
    connection.row_factory = sqlite3.Row
    assert resolve_action_preview(connection, historical)[2] is None
    with pytest.raises(ValueError, match="requires a real plan"):
        validate_capture_payload(_payload(rx, data={"mode": "planned"}))
    with pytest.raises(ValueError, match="cannot reference a plan"):
        validate_capture_payload(_payload(rx, data={"planned_event_ref": "medevt_" + "a" * 24}))

    connection.execute(
        """UPDATE medication_administrations
               SET planned_quantity_value='1',planned_dosage_form='Tablette',planned_strength='10 mg',
                   route_original='oral',route_normalized='oral'
             WHERE lower(event_type)='planned'"""
    )
    connection.commit()
    planned_api = dispatch_api(database, "/api/v1/medications", "")
    plan = planned_api["planned"][0]
    active = next(item for item in planned_api["prescriptions"] if item["id"] == plan["prescription_id"])
    planned_payload = validate_capture_payload(
        _payload(
            rx,
            data={
                "mode": "planned", "medication_ref": active["id"],
                "planned_event_ref": plan["id"], "name": active["name"],
                "quantity_value": "1", "dosage_form": "Tablette", "strength": "10 mg",
                "route_original": "oral", "route_normalized": "oral",
                "injection_region": "", "injection_side": "", "injection_detail": "",
                "preset_revision": plan["administration_preset"]["preset_revision"],
            },
        )
    )
    revision, _, resolved_plan, _ = resolve_action_preview(connection, planned_payload)
    assert revision and resolved_plan is not None
    planned_payload["data"]["preview_revision"] = revision
    connection.close()
    media_dir=tmp_path/"planned-media";quarantine_dir=tmp_path/"planned-quarantine";media_dir.mkdir();quarantine_dir.mkdir()
    monkeypatch.setattr(worker,"DASHBOARD_DB",database)
    monkeypatch.setattr(worker,"CAPTURE_MEDIA",media_dir)
    monkeypatch.setattr(worker,"CAPTURE_QUARANTINE",quarantine_dir)
    worker.apply_capture_action(planned_payload)
    connection=sqlite3.connect(database)
    snapshot=connection.execute(
        """SELECT planned_quantity_value,planned_dosage_form,planned_strength,
                  actual_quantity_value,actual_dosage_form,actual_strength
             FROM medication_administrations
            WHERE source='dashboard_medication_action_version_two' AND planned_event_id IS NOT NULL"""
    ).fetchone()
    assert snapshot == ("1","Tablette","10 mg","1","Tablette","10 mg")


def test_ui_contract_separates_fields_modes_and_repairs_day_symptom_button() -> None:
    record = (ROOT / "scripts/health/assets/health-assets/dashboard-v5-record.js").read_text(encoding="utf-8")
    capture = record[record.index("function administrationCaptureDialog"):record.index("async function renderMedications")]
    for label in ("Menge", "Darreichungsform", "Wirkstoffstärke", "Applikationsweg", "Injektionsstelle (optional)", "Notiz (optional)"):
        assert label in capture
    assert "health.medication_action.v2" in capture
    assert "Historische manuelle Gabe ohne Plantermin" in capture
    assert "Aus bestehender Medikamentenplanung" not in capture
    assert "Planwert bewusst übernommen" not in capture
    assert "Abweichung vom Plan bestätigt" not in capture
    assert "Geplanten Termin dokumentieren" in record
    assert "Historische Einnahme/Gabe erfassen" in record
    assert "aria-labelledby','medication-administration-title" in record
    assert "baseline?.route_original||''" in record
    assert "route.value==='subcutaneous'?'subkutan'" not in record
    assert "quantity.type='number'" in capture
    assert "['Spritze','Spritze']" in capture
    assert "correction_administration_preset" in capture
    assert "bind_verified_preset:Boolean(preset.bind_verified_preset)" in record
    assert "medicationRouteLabel" in record and "subcutaneous:'Subkutan'" in record
    assert "medicationSideLabel" in record and "right:'Rechts'" in record
    assert "Tatsächliche Wirkstoffstärke" in record
    assert "fetch('/health-actions/capture'" in capture
    assert "/api/v1/capture/status/${statusKey}/${statusToken}" in capture
    assert "Eingaben und identische Aktion bleiben erhalten" in capture

    main = (ROOT / "scripts/health/assets/health-assets/dashboard-v5.js").read_text(encoding="utf-8")
    day = (ROOT / "scripts/health/assets/health-assets/dashboard-v5-day-controller.js").read_text(encoding="utf-8")
    assert "window.healthOpenSymptomCheckin = openSymptomCheckin" in main
    assert 'dialog.querySelector("input[name=date]")' in main
    assert 'input[name=date]' in main
    assert "let currentDay = dayRoute(new URLSearchParams(location.search)) || today" in day
    assert "currentDay=input.date" in day
    assert "if(!routed)currentDay=today" in day
    assert "window.healthOpenSymptomCheckin(date)" in day
    assert "#open-checkin" not in day
    capture_hub = (ROOT / "scripts/health/assets/health-assets/dashboard-v5-capture.js").read_text(encoding="utf-8")
    assert "openMedicationRecord" in capture_hub
    assert "window.healthRecordOpenTab('medications')" in capture_hub
