from __future__ import annotations

import json
import re
import sqlite3
import sys
from datetime import datetime, timezone
from pathlib import Path

import pytest

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

from dashboard_v5.source_status import (
    CONTRACT_VERSION,
    build_source_status,
    classify_freshness,
    derive_regeneration,
    validate_public_payload,
)

NOW = datetime(2026, 8, 15, 10, 0, tzinfo=timezone.utc)
COMMIT = "1" * 40


def schema(connection: sqlite3.Connection) -> None:
    connection.executescript(
        """
        CREATE TABLE apple_health_records(end_date TEXT, imported_at TEXT);
        CREATE TABLE apple_health_import_files(status TEXT, imported_at TEXT, last_attempt_at TEXT);
        CREATE TABLE nutrition_items(datum TEXT, imported_at TEXT, updated_at TEXT);
        CREATE TABLE sync_state(key TEXT, updated_at TEXT);
        CREATE TABLE nutrition_review_queue(status TEXT);
        CREATE TABLE laborwerte(abnahme_datum TEXT, befund_datum TEXT, ermittlung_datum TEXT);
        CREATE TABLE laborwerte_staging(status TEXT);
        CREATE TABLE dokumente(document_date TEXT);
        CREATE TABLE document_processing(updated_at TEXT);
        CREATE TABLE health_processing_runs(run_type TEXT, started_at TEXT, finished_at TEXT, status TEXT);
        CREATE TABLE document_candidates(status TEXT);
        CREATE TABLE document_reconciliation(conflict_count INTEGER);
        CREATE TABLE symptom_log(datum TEXT, occurred_at TEXT, created_at TEXT, kontext TEXT);
        CREATE TABLE health_events(date TEXT, occurred_at TEXT, created_at TEXT, source TEXT, category TEXT);
        """
    )


def artifact(path: Path, generated_at: str = "2026-08-14T20:00:00Z") -> Path:
    bundle = {"generated_at": generated_at}
    path.write_text(
        f"<meta name='health-runtime-commit' content='{COMMIT}'>"
        f"<meta name='health-runtime-build-id' content='v5-{COMMIT[:12]}'>"
        "<script type='application/json' id='health-dashboard-bundle'>" + json.dumps(bundle) + "</script>"
    )
    return path


def fixture(connection: sqlite3.Connection) -> None:
    connection.executescript(
        """
        INSERT INTO apple_health_records VALUES ('2026-08-10T20:00:00Z','2026-08-15T08:00:00Z');
        INSERT INTO apple_health_import_files VALUES ('imported','2026-08-15T08:00:00Z','2026-08-15T08:00:00Z');
        INSERT INTO nutrition_items VALUES ('2026-07-21','2026-07-21T20:00:00Z','2026-07-21T20:00:00Z');
        INSERT INTO sync_state VALUES ('yazio:2026-08-14:v2:fingerprint','2026-08-14T21:15:00Z');
        INSERT INTO nutrition_review_queue VALUES ('open');
        INSERT INTO laborwerte VALUES ('2026-06-09',NULL,'2026-06-10T12:00:00Z');
        INSERT INTO dokumente VALUES ('2026-06-28');
        INSERT INTO document_processing VALUES ('2026-08-15T09:00:00Z');
        INSERT INTO health_processing_runs VALUES ('full_document_reprocess','2026-08-15T08:30:00Z','2026-08-15T08:31:00Z','completed');
        INSERT INTO health_processing_runs VALUES ('full_document_reprocess','2026-08-15T09:30:00Z','2026-08-15T09:31:00Z','failed');
        INSERT INTO document_candidates VALUES ('open');
        INSERT INTO document_reconciliation VALUES (1);
        INSERT INTO symptom_log VALUES ('2026-08-12',NULL,'2026-08-12T10:00:00Z','telegram_user_report');
        INSERT INTO health_events VALUES ('2026-08-11',NULL,'2026-08-11T10:00:00Z','telegram_user_report','MEDIKAMENT');
        """
    )


def test_freshness_dimensions_are_explicit() -> None:
    assert classify_freshness(configured=False, cadence_kind="daily", last_success=None, now=NOW, max_delay_days=1) == "not_configured"
    assert classify_freshness(configured=True, cadence_kind="event_based", last_success=None, now=NOW) == "not_expected"
    assert classify_freshness(configured=True, cadence_kind="unknown", last_success=None, now=NOW) == "unknown"
    assert classify_freshness(configured=True, cadence_kind="daily", last_success="2026-08-15T08:00:00Z", now=NOW, max_delay_days=1) == "current"
    assert classify_freshness(configured=True, cadence_kind="daily", last_success="2026-08-10T08:00:00Z", now=NOW, max_delay_days=1) == "delayed"


def test_regeneration_pending_is_independent() -> None:
    assert derive_regeneration("2026-08-15T09:00:00Z", "2026-08-15T08:00:00Z", artifact_available=True) == "pending"
    assert derive_regeneration("2026-08-15T07:00:00Z", "2026-08-15T08:00:00Z", artifact_available=True) == "current"
    assert derive_regeneration(None, "2026-08-15T08:00:00Z", artifact_available=True) == "unknown"
    assert derive_regeneration(None, None, artifact_available=False) == "failed"


def test_contract_separates_data_import_review_and_regeneration(tmp_path: Path) -> None:
    connection = sqlite3.connect(":memory:")
    schema(connection); fixture(connection)
    payload = build_source_status(connection, artifact_path=artifact(tmp_path / "runtime.html"), now=NOW)
    by_key = {item["source_key"]: item for item in payload["sources"]}
    apple = by_key["apple_health_metrics"]
    assert apple["actual_data_through"] == "2026-08-10"
    assert apple["last_import_success_at"] == "2026-08-15T08:00:00Z"
    assert apple["freshness"] == "current"
    assert apple["import_state"] == "success"
    assert apple["regeneration_state"] == "pending"
    assert by_key["nutrition_yazio"]["freshness"] == "current"
    assert by_key["nutrition_yazio"]["import_state"] == "success"
    assert by_key["nutrition_yazio"]["review_state"] == "review_open"
    assert by_key["documents_ocr"]["import_state"] == "failed"
    assert by_key["documents_ocr"]["review_state"] == "conflict"
    assert by_key["telegram_symptoms"]["freshness"] == "not_expected"
    assert by_key["laboratory"]["freshness"] == "not_expected"
    assert by_key["dashboard_v5"]["regeneration_state"] == "pending"
    connection.close()


def test_workouts_without_container_are_not_failed_or_delayed(tmp_path: Path) -> None:
    connection = sqlite3.connect(":memory:"); schema(connection)
    payload = build_source_status(connection, artifact_path=artifact(tmp_path / "runtime.html"), now=NOW)
    workout = next(item for item in payload["sources"] if item["source_key"] == "apple_health_workouts")
    assert workout["configured"] is False
    assert workout["freshness"] == "not_configured"
    assert workout["import_state"] == "never_run"
    assert workout["availability"] == "unknown"
    assert workout["action"]["target"] == "workout-export-help"
    connection.close()


def test_no_new_nutrition_record_is_not_an_import_error(tmp_path: Path) -> None:
    connection = sqlite3.connect(":memory:"); schema(connection)
    connection.execute("INSERT INTO nutrition_items VALUES (?,?,?)", ("2026-01-01", "2026-01-01T12:00:00Z", "2026-01-01T12:00:00Z"))
    connection.execute("INSERT INTO sync_state VALUES (?,?)", ("yazio:2026-08-14:v2:fingerprint", "2026-08-14T21:15:00Z"))
    payload = build_source_status(connection, artifact_path=artifact(tmp_path / "runtime.html", "2026-08-15T09:00:00Z"), now=NOW)
    nutrition = next(item for item in payload["sources"] if item["source_key"] == "nutrition_yazio")
    assert nutrition["actual_data_through"] == "2026-01-01"
    assert nutrition["import_state"] == "success"
    assert nutrition["freshness"] == "current"
    connection.close()


def test_payload_is_bounded_and_redacted(tmp_path: Path) -> None:
    connection = sqlite3.connect(":memory:"); schema(connection)
    payload = build_source_status(connection, artifact_path=artifact(tmp_path / "runtime.html"), now=NOW)
    text = json.dumps(payload)
    assert payload["contract_version"] == CONTRACT_VERSION
    assert len(payload["sources"]) == 8
    assert not re.search(r"/home/|/tmp/|\.pdf\b|\.json\b|\.db\b|drive", text, re.I)
    assert "stack" not in text.lower()
    connection.close()


def test_redaction_guard_rejects_private_path() -> None:
    with pytest.raises(ValueError, match="private status detail"):
        validate_public_payload({"sources": [{
            "availability": "available", "freshness": "current", "import_state": "success",
            "review_state": "none", "regeneration_state": "current", "explanation": "/home/private/file",
        }]})
