import json
import sqlite3
from pathlib import Path

from synthneura.core.schemas import ClinicalTrial
from synthneura.storage.sqlite_sink import SQLiteTrialSink


def test_store_trial_change_detection(tmp_path: Path) -> None:
    db_path = str(tmp_path / "trials.db")
    trial = ClinicalTrial(
        nct_id="NCT00000003",
        title="Test Trial",
        status="RECRUITING",
        phase="PHASE1",
        sponsor="Acme",
        conditions=["A"],
        interventions=["Drug X"],
        outcomes=["Outcome 1"],
    )

    sink = SQLiteTrialSink(db_path)
    result_new = sink.store_trials(
        [trial],
        [],
        {
            "run_id": "run-1",
            "ingested_at": "2026-01-01T00:00:00Z",
            "source": "clinicaltrials.gov",
            "query": "cancer",
        },
    )
    assert result_new.counts["new"] == 1

    result_same = sink.store_trials(
        [trial],
        [],
        {
            "run_id": "run-2",
            "ingested_at": "2026-01-01T01:00:00Z",
            "source": "clinicaltrials.gov",
            "query": "cancer",
        },
    )
    assert result_same.counts["unchanged"] == 1

    if hasattr(trial, "model_copy"):
        updated_trial = trial.model_copy(update={"status": "COMPLETED"})
    else:
        updated_trial = trial.copy(update={"status": "COMPLETED"})
    result_updated = sink.store_trials(
        [updated_trial],
        [],
        {
            "run_id": "run-3",
            "ingested_at": "2026-01-01T02:00:00Z",
            "source": "clinicaltrials.gov",
            "query": "cancer",
        },
    )
    assert result_updated.counts["updated"] == 1
    assert result_updated.changes
    assert result_updated.changes[0].before["status"] == "RECRUITING"
    assert result_updated.changes[0].after["status"] == "COMPLETED"

    conn = sqlite3.connect(db_path)
    try:
        cursor = conn.cursor()
        cursor.execute(
            """
            SELECT nct_id, status, valid_from, valid_to
            FROM clinical_trials_history
            WHERE nct_id = ?
            """,
            (trial.nct_id,),
        )
        row = cursor.fetchone()
        cursor.execute(
            """
            SELECT nct_id, changed_fields, before_json, after_json
            FROM trial_diffs
            WHERE nct_id = ?
            """,
            (trial.nct_id,),
        )
        diff_row = cursor.fetchone()
    finally:
        conn.close()

    assert row is not None
    assert row[1] == "RECRUITING"
    assert row[2] == "2026-01-01T00:00:00Z"
    assert row[3] == "2026-01-01T02:00:00Z"
    assert diff_row is not None
    changed_fields = json.loads(diff_row[1])
    before = json.loads(diff_row[2])
    after = json.loads(diff_row[3])
    assert "status" in changed_fields
    assert before["status"] == "RECRUITING"
    assert after["status"] == "COMPLETED"

    previous_time = sink.fetch_previous_run_time("run-3")
    diffs = sink.fetch_diffs_between(previous_time, "2026-01-01T02:00:00Z")
    assert diffs
    assert diffs[0].before["status"] == "RECRUITING"
    assert diffs[0].after["status"] == "COMPLETED"

    sink.store_extractions(
        nct_id=trial.nct_id,
        endpoints=["Overall survival"],
        biomarkers=["EGFR"],
        run_id="run-3",
        ingested_at="2026-01-01T02:00:00Z",
        provider="openai",
        model="gpt-4o-mini",
    )
    conn = sqlite3.connect(db_path)
    try:
        cursor = conn.cursor()
        cursor.execute(
            """
            SELECT endpoints_json, biomarkers_json, provider, model
            FROM trial_extractions
            WHERE nct_id = ?
            """,
            (trial.nct_id,),
        )
        extraction_row = cursor.fetchone()
    finally:
        conn.close()

    assert extraction_row is not None
    assert json.loads(extraction_row[0]) == ["Overall survival"]
    assert json.loads(extraction_row[1]) == ["EGFR"]
    assert extraction_row[2] == "openai"
    assert extraction_row[3] == "gpt-4o-mini"

    sink.store_extraction_failure(
        nct_id=trial.nct_id,
        run_id="run-3",
        ingested_at="2026-01-01T02:00:00Z",
        provider="openai",
        model="gpt-4o-mini",
        error="boom",
    )
    conn = sqlite3.connect(db_path)
    try:
        cursor = conn.cursor()
        cursor.execute(
            """
            SELECT provider, model, error
            FROM trial_extraction_failures
            WHERE nct_id = ?
            """,
            (trial.nct_id,),
        )
        failure_row = cursor.fetchone()
    finally:
        conn.close()

    assert failure_row is not None
    assert failure_row[0] == "openai"
    assert failure_row[1] == "gpt-4o-mini"
    assert failure_row[2] == "boom"


def test_store_extractions_with_metadata(tmp_path: Path) -> None:
    db_path = str(tmp_path / "trials.db")
    sink = SQLiteTrialSink(db_path)
    sink.store_extractions(
        nct_id="NCT00000010",
        endpoints=[{"normalized_name": "Progression-Free Survival (PFS)"}],
        biomarkers=[{"normalized_name": "EGFR"}],
        run_id="run-meta",
        ingested_at="2026-01-02T00:00:00Z",
        provider="openai",
        model="gpt-4o-mini",
        prompt_version="v4-endpoint-biomarker-1",
        raw_response='{"endpoints":[],"biomarkers":[]}',
        validation_status="valid",
        validation_errors=["warn"],
        confidence=0.75,
    )

    conn = sqlite3.connect(db_path)
    try:
        cursor = conn.cursor()
        cursor.execute(
            """
            SELECT prompt_version, raw_response, validation_status, validation_errors,
                   confidence
            FROM trial_extractions
            WHERE nct_id = ?
            """,
            ("NCT00000010",),
        )
        row = cursor.fetchone()
    finally:
        conn.close()

    assert row is not None
    assert row[0] == "v4-endpoint-biomarker-1"
    assert row[1] == '{"endpoints":[],"biomarkers":[]}'
    assert row[2] == "valid"
    assert json.loads(row[3]) == ["warn"]
    assert row[4] == 0.75
