import sqlite3
from datetime import datetime, timezone

import pytest

from synthneura.storage.sqlite_sink import _ensure_schema
from synthneura.ui.web import app as web_app


@pytest.fixture()
def db_path(tmp_path) -> str:
    return str(tmp_path / "trials.db")


@pytest.fixture()
def client(db_path, monkeypatch):
    db_url = f"sqlite:///{db_path}"
    monkeypatch.setenv("SYNTHNEURA_DB_URL", db_url)
    web_app.DEFAULT_DB_URL = db_url
    with web_app.app.test_client() as client:
        yield client


def _seed_run(conn: sqlite3.Connection, run_id: str, query: str, total: int) -> None:
    ingested_at = datetime.now(timezone.utc).isoformat(timespec="seconds")
    conn.execute(
        """
        INSERT INTO runs (
            run_id, ingested_at, source, query, total,
            new_count, updated_count, unchanged_count, failed_count
        )
        VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
        """,
        (run_id, ingested_at, "clinicaltrials.gov", query, total, total, 0, 0, 0),
    )


def _seed_trials(conn: sqlite3.Connection, run_id: str, count: int, query: str) -> None:
    for idx in range(count):
        nct_id = f"NCT{idx:08d}"
        conn.execute(
            """
            INSERT OR REPLACE INTO clinical_trials (
                nct_id, title, status, phase, sponsor,
                conditions, interventions, outcomes, raw_json,
                source, query, ingested_at, run_id
            )
            VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
            """,
            (
                nct_id,
                f"Trial {idx}",
                "RECRUITING",
                "PHASE2",
                "Acme",
                "Condition A",
                "Drug X",
                "Outcome 1",
                "{}",
                "clinicaltrials.gov",
                query,
                datetime.now(timezone.utc).isoformat(timespec="seconds"),
                run_id,
            ),
        )


def test_trials_pagination(client, db_path):
    run_id = "run-1"
    with sqlite3.connect(db_path) as conn:
        _ensure_schema(conn)
        _seed_run(conn, run_id, "cancer", 30)
        _seed_trials(conn, run_id, 30, "cancer")
        conn.commit()

    resp = client.get("/api/trials?page=2&page_size=10&run_id=run-1")
    assert resp.status_code == 200
    data = resp.get_json()
    assert data["page"] == 2
    assert data["page_size"] == 10
    assert data["total"] == 30
    assert len(data["trials"]) == 10


def test_overview_baseline_flag(client, db_path):
    run_id = "run-2"
    with sqlite3.connect(db_path) as conn:
        _ensure_schema(conn)
        _seed_run(conn, run_id, "melanoma", 5)
        _seed_trials(conn, run_id, 5, "melanoma")
        conn.execute(
            """
            UPDATE runs
            SET new_count = 5, updated_count = 0, unchanged_count = 0
            WHERE run_id = ?
            """,
            (run_id,),
        )
        conn.commit()

    resp = client.get("/api/overview?run_id=run-2")
    assert resp.status_code == 200
    data = resp.get_json()
    assert data["baseline"] is True
    assert data["run"]["run_id"] == run_id


def test_chat_limit(client, db_path, monkeypatch):
    monkeypatch.setenv("SYNTHNEURA_OPENAI_API_KEY", "test-key")
    web_app.CHAT_DAILY_TOKENS = 5
    with sqlite3.connect(db_path) as conn:
        _ensure_schema(conn)
        _seed_run(conn, "run-3", "cancer", 1)
        _seed_trials(conn, "run-3", 1, "cancer")
        conn.commit()

    resp = client.post(
        "/api/chat",
        json={
            "message": "This message is definitely longer than five tokens",
            "user_id": "demo",
        },
    )
    assert resp.status_code == 429
    data = resp.get_json()
    assert data["detail"] == "Daily token limit reached."


def test_chat_latest_runs(client, db_path, monkeypatch):
    monkeypatch.setenv("SYNTHNEURA_OPENAI_API_KEY", "test-key")
    with sqlite3.connect(db_path) as conn:
        _ensure_schema(conn)
        _seed_run(conn, "run-4", "melanoma", 3)
        _seed_trials(conn, "run-4", 3, "melanoma")
        conn.commit()

    resp = client.post("/api/chat", json={"message": "latest runs", "user_id": "demo"})
    assert resp.status_code == 200
    data = resp.get_json()
    assert "Latest runs" in data["reply"]


def test_filters_include_endpoints_and_biomarkers(client, db_path):
    run_id = "run-5"
    with sqlite3.connect(db_path) as conn:
        _ensure_schema(conn)
        _seed_run(conn, run_id, "melanoma", 1)
        _seed_trials(conn, run_id, 1, "melanoma")
        conn.execute(
            """
            INSERT INTO trial_extractions (
                nct_id, run_id, ingested_at, endpoints_json, biomarkers_json,
                provider, model, prompt_version, raw_response, validation_status,
                validation_errors, confidence
            )
            VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
            """,
            (
                "NCT00000001",
                run_id,
                datetime.now(timezone.utc).isoformat(timespec="seconds"),
                '[{"normalized_name": "Progression-Free Survival (PFS)"}]',
                '[{"normalized_name": "EGFR"}]',
                "openai",
                "gpt-4o-mini",
                "test",
                "{}",
                "valid",
                "[]",
                1.0,
            ),
        )
        conn.commit()

    resp = client.get("/api/filters")
    assert resp.status_code == 200
    data = resp.get_json()
    assert "oncology" in data["disease_categories"]
    assert "Progression-Free Survival (PFS)" in data["endpoints"]
    assert "EGFR" in data["biomarkers"]


def test_overview_signal_ranking_and_extraction_diff(client, db_path):
    run_id = "run-6"
    ingested_at = datetime.now(timezone.utc).isoformat(timespec="seconds")
    with sqlite3.connect(db_path) as conn:
        _ensure_schema(conn)
        _seed_run(conn, run_id, "melanoma", 2)
        _seed_trials(conn, run_id, 2, "melanoma")
        conn.execute(
            """
            UPDATE clinical_trials
            SET phase = ?, status = ?
            WHERE nct_id = ?
            """,
            ("PHASE3", "RECRUITING", "NCT00000000"),
        )
        conn.execute(
            """
            UPDATE clinical_trials
            SET phase = ?, status = ?
            WHERE nct_id = ?
            """,
            ("PHASE1", "ACTIVE", "NCT00000001"),
        )
        conn.execute(
            """
            INSERT INTO trial_diffs (
                nct_id, run_id, ingested_at, changed_fields, before_json, after_json
            )
            VALUES (?, ?, ?, ?, ?, ?)
            """,
            (
                "NCT00000000",
                run_id,
                ingested_at,
                '["status", "phase"]',
                '{"status": "COMPLETED"}',
                '{"status": "RECRUITING"}',
            ),
        )
        conn.execute(
            """
            INSERT INTO trial_diffs (
                nct_id, run_id, ingested_at, changed_fields, before_json, after_json
            )
            VALUES (?, ?, ?, ?, ?, ?)
            """,
            (
                "NCT00000001",
                run_id,
                ingested_at,
                '["status"]',
                '{"status": "COMPLETED"}',
                '{"status": "ACTIVE"}',
            ),
        )
        conn.execute(
            """
            INSERT INTO trial_extractions (
                nct_id, run_id, ingested_at, endpoints_json, biomarkers_json,
                provider, model, prompt_version, raw_response, validation_status,
                validation_errors, confidence
            )
            VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
            """,
            (
                "NCT00000000",
                run_id,
                ingested_at,
                '[{"normalized_name": "Progression-Free Survival (PFS)"}]',
                '[{"normalized_name": "EGFR"}]',
                "openai",
                "gpt-4o-mini",
                "test",
                "{}",
                "valid",
                "[]",
                1.0,
            ),
        )
        conn.execute(
            """
            INSERT INTO trial_extractions (
                nct_id, run_id, ingested_at, endpoints_json, biomarkers_json,
                provider, model, prompt_version, raw_response, validation_status,
                validation_errors, confidence
            )
            VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
            """,
            (
                "NCT00000001",
                run_id,
                ingested_at,
                '[{"normalized_name": "Overall Survival (OS)"}]',
                "[]",
                "openai",
                "gpt-4o-mini",
                "test",
                "{}",
                "valid",
                "[]",
                1.0,
            ),
        )
        conn.execute(
            """
            INSERT INTO trial_extraction_diffs (
                nct_id, run_id, ingested_at, endpoints_added, endpoints_removed,
                biomarkers_added, biomarkers_removed, prompt_version
            )
            VALUES (?, ?, ?, ?, ?, ?, ?, ?)
            """,
            (
                "NCT00000001",
                run_id,
                ingested_at,
                '["Overall Survival (OS)"]',
                "[]",
                "[]",
                "[]",
                "test",
            ),
        )
        conn.commit()

    resp = client.get(f"/api/overview?run_id={run_id}")
    assert resp.status_code == 200
    data = resp.get_json()
    signals = data["signals"]
    assert signals
    assert signals[0]["nct_id"] == "NCT00000000"
    assert any(signal.get("signal_type") == "extraction_diff" for signal in signals)
