from __future__ import annotations

# ruff: noqa: E402

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

import pytest

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

from dashboard_v5.document_originals import MAX_ORIGINAL_BYTES, probe_original
from dashboard_v5.read_api import APIError, dispatch_api
from dashboard_v5.render import render
from fixtures.dashboard_v5_fixture import build_dashboard_v5_fixture


def _insert_document(connection, *, name, path, review, content, day):
    connection.execute(
        """INSERT INTO dokumente(
               datei_name,dateipfad,daten_typ,kategorie,institution,review_status,
               document_date,extrahierte_inhalte,groessekbytes,datei_hash
           ) VALUES(?,?,?,?,?,?,?,?,?,?)""",
        (name, path, "pdf", "SYNTHETIC_6E4B", "SYNTHETIC_CLINIC", review, day, content, 1, f"hash-{day}"),
    )


def test_document_history_projects_explicit_fail_closed_statuses(tmp_path, monkeypatch):
    database = tmp_path / "fixture.db"
    originals = tmp_path / "originals"
    originals.mkdir()
    (originals / "available.pdf").write_bytes(b"%PDF-1.7\nsynthetic")
    (originals / "unsupported.pdf").write_bytes(b"not-a-pdf")
    build_dashboard_v5_fixture(database)
    connection = sqlite3.connect(database)
    _insert_document(connection, name="available.pdf", path="available.pdf", review="geprueft", content="SYNTHETIC CONTENT", day="2026-07-01")
    _insert_document(connection, name="pending.pdf", path="available.pdf", review="nicht_geprueft", content="SYNTHETIC PENDING", day="2026-07-02")
    _insert_document(connection, name="unsupported.pdf", path="unsupported.pdf", review="geprueft", content="", day="2026-07-03")
    _insert_document(connection, name="missing.pdf", path="missing.pdf", review="geprueft", content="SYNTHETIC MISSING", day="2026-07-04")
    connection.commit()
    connection.close()
    monkeypatch.setenv("HEALTH_DASHBOARD_ORIGINAL_ROOTS", str(originals))

    payload = dispatch_api(database, "/api/v1/documents", "category=SYNTHETIC_6E4B&limit=10")
    assert len(payload["documents"]) == 4
    by_day = {item["document_date"]: item for item in payload["documents"]}
    assert (by_day["2026-07-01"]["content_status"], by_day["2026-07-01"]["original_status"]) == ("extracted", "available")
    assert (by_day["2026-07-02"]["extraction_status"], by_day["2026-07-02"]["original_status"]) == ("extracted", "available")
    assert (by_day["2026-07-03"]["content_status"], by_day["2026-07-03"]["original_status"]) == ("not_extracted", "unsupported")
    assert by_day["2026-07-04"]["original_status"] == "missing"
    assert by_day["2026-07-02"]["search_status"] == "extracted_not_reviewed"
    assert payload["coverage"] == {
        "total": 4,
        "original_available": 2,
        "original_missing": 1,
        "original_unsupported": 1,
        "original_blocked": 0,
        "original_too_large": 0,
        "original_unavailable": 2,
        "text_extracted": 3,
        "content_reviewed": 3,
        "fulltext_searchable": 0,
    }
    detail = dispatch_api(database, f"/api/v1/documents/{by_day['2026-07-01']['id']}", "")
    assert detail["content_status"] == "available"
    assert detail["document_date_status"] == "known"
    assert detail["original_status"] == "available"
    assert detail["original_available"] is True
    with pytest.raises(APIError) as pending:
        dispatch_api(database, f"/api/v1/documents/{by_day['2026-07-02']['id']}", "")
    assert pending.value.status == 404
    preview = dispatch_api(database, f"/api/v1/documents/{by_day['2026-07-02']['id']}/extracted-preview", "")
    assert preview["notice"] == "Maschinell extrahierter Inhalt – noch nicht inhaltlich geprüft"
    assert preview["search_status"] == "extracted_not_reviewed"
    serialized = json.dumps(payload)
    assert str(originals) not in serialized
    assert not any(name in serialized for name in ("available.pdf", "pending.pdf", "unsupported.pdf", "missing.pdf"))


def test_shared_original_probe_blocks_symlinks_roots_magic_and_size(tmp_path):
    root = tmp_path / "root"
    root.mkdir()
    pdf = root / "ok.pdf"
    png = root / "ok.png"
    bad = root / "bad.pdf"
    large = root / "large.pdf"
    outside = tmp_path / "outside.pdf"
    pdf.write_bytes(b"%PDF-1.7\nsynthetic")
    png.write_bytes(b"\x89PNG\r\n\x1a\nsynthetic")
    bad.write_bytes(b"wrong-magic")
    outside.write_bytes(b"%PDF-1.7\nsynthetic")
    with large.open("wb") as handle:
        handle.write(b"%PDF-")
        handle.truncate(MAX_ORIGINAL_BYTES + 1)
    symlink = root / "link.pdf"
    symlink.symlink_to(pdf)

    for candidate, expected in ((pdf, "available"), (png, "available"), (bad, "unsupported"), (large, "too_large"), (outside, "blocked"), (symlink, "blocked"), (root / "missing.pdf", "missing")):
        result = probe_original(candidate, reviewed=True, roots=(root,))
        try:
            assert result.status == expected
        finally:
            result.close()
    independent = probe_original(pdf, reviewed=False, roots=(root,))
    try:
        assert independent.status == "available"
    finally:
        independent.close()


def test_v5_render_bundles_pinned_fullcalendar_and_reusable_components(tmp_path):
    from dashboard_v5.data_provider import build_bundle

    database = tmp_path / "render.db"
    build_dashboard_v5_fixture(database)
    connection = sqlite3.connect(database)
    connection.row_factory = sqlite3.Row
    try:
        bundle = build_bundle(connection, today="2026-07-16", generated_at="2026-07-16T12:00:00+00:00")
    finally:
        connection.close()
    html = render(bundle, explorer_6c=True, calendar_day_6d=True, health_record_6e=True)
    assert "/health-assets/fullcalendar-6.1.21.min.js" in html
    assert "data-calendar-range-from" in html and "data-calendar-range-to" in html
    assert "data-day-context" in html and "data-day-missing" in html
    assert "data-record-breadcrumb" in html
    css = (ROOT / "scripts/health/assets/health-assets/dashboard-v5.css").read_text(encoding="utf-8")
    for contract in ("--v5-space-1", ".v5-grid-12", ".button-primary", ".status-chip", ".v5-skeleton"):
        assert contract in css


def test_fullcalendar_notice_is_pinned_mit_and_standard_only():
    notice = (ROOT / "THIRD_PARTY_NOTICES.md").read_text(encoding="utf-8")
    assert "FullCalendar Standard 6.1.21" in notice
    assert "MIT" in notice
    assert "No FullCalendar Premium or Scheduler" in notice
    assets = ROOT / "scripts/health/assets/health-assets"
    metadata = json.loads((assets / "fullcalendar-6.1.21.metadata.json").read_text(encoding="utf-8"))
    bundle = assets / "fullcalendar-6.1.21.min.js"
    license_file = assets / metadata["license_file"]
    assert metadata["version"] == "6.1.21"
    assert metadata["license"] == "MIT"
    assert hashlib.sha256(bundle.read_bytes()).hexdigest() == metadata["sha256"]
    assert hashlib.sha256(license_file.read_bytes()).hexdigest() == metadata["license_sha256"]
    assert "MIT License" in license_file.read_text(encoding="utf-8")
