"""Integration tests for app.api.v1.mdt — multidisciplinary team case management."""

import uuid

import pytest

from app.models.user import Tenant


@pytest.mark.asyncio
async def test_list_cases_no_auth(client):
    """GET /mdt/cases without auth returns 401."""
    r = await client.get("/api/v1/mdt/cases")
    assert r.status_code == 401


@pytest.mark.asyncio
async def test_list_cases_empty(client, auth_headers):
    """GET /mdt/cases with auth returns empty list."""
    r = await client.get("/api/v1/mdt/cases", headers=auth_headers)
    assert r.status_code == 200
    data = r.json()
    assert data["items"] == []
    assert data["total"] == 0


@pytest.mark.asyncio
async def test_create_case(client, auth_headers):
    """Create a new MDT case."""
    r = await client.post("/api/v1/mdt/cases", headers=auth_headers, json={
        "title": "Lung Cancer MDT Case",
        "patient_summary": "65-year-old male, stage IV NSCLC",
        "cancer_type": "Lung",
    })
    assert r.status_code == 200
    data = r.json()
    assert data["status"] == "created"
    case = data["case"]
    assert case["title"] == "Lung Cancer MDT Case"
    assert case["cancer_type"] == "Lung"
    assert case["status"] == "open"
    assert "id" in case
    assert "created_at" in case
    return case["id"]


@pytest.mark.asyncio
async def test_create_case_minimal(client, auth_headers):
    """Create an MDT case with only required fields."""
    r = await client.post("/api/v1/mdt/cases", headers=auth_headers, json={
        "title": "Minimal Case",
        "patient_summary": "Brief summary",
    })
    assert r.status_code == 200
    data = r.json()
    assert data["status"] == "created"
    assert data["case"]["cancer_type"] is None


@pytest.mark.asyncio
async def test_create_then_list_cases(client, auth_headers):
    """Created case appears in the list."""
    r = await client.post("/api/v1/mdt/cases", headers=auth_headers, json={
        "title": "List Test Case",
        "patient_summary": "Test for listing",
    })
    assert r.status_code == 200
    case_id = r.json()["case"]["id"]

    r = await client.get("/api/v1/mdt/cases", headers=auth_headers)
    assert r.status_code == 200
    data = r.json()
    assert data["total"] >= 1
    ids = {c["id"] for c in data["items"]}
    assert case_id in ids


@pytest.mark.asyncio
async def test_get_case_by_id(client, auth_headers):
    """Get a specific MDT case by ID."""
    r = await client.post("/api/v1/mdt/cases", headers=auth_headers, json={
        "title": "Get By ID Case",
        "patient_summary": "Detailed patient info",
        "cancer_type": "Breast",
    })
    assert r.status_code == 200
    case_id = r.json()["case"]["id"]

    r = await client.get(f"/api/v1/mdt/cases/{case_id}", headers=auth_headers)
    assert r.status_code == 200
    data = r.json()
    assert data["id"] == case_id
    assert data["title"] == "Get By ID Case"
    assert data["cancer_type"] == "Breast"
    assert data["status"] == "open"


@pytest.mark.asyncio
async def test_get_case_not_found(client, auth_headers):
    """Get non-existent case (valid UUID but not found) returns 404."""
    fake_id = str(uuid.uuid4())
    r = await client.get(f"/api/v1/mdt/cases/{fake_id}", headers=auth_headers)
    assert r.status_code == 404


@pytest.mark.asyncio
async def test_add_decision(client, auth_headers):
    """Add a decision to an MDT case."""
    r = await client.post("/api/v1/mdt/cases", headers=auth_headers, json={
        "title": "Decision Case",
        "patient_summary": "Patient for decision testing",
    })
    assert r.status_code == 200
    case_id = r.json()["case"]["id"]

    r = await client.post(f"/api/v1/mdt/cases/{case_id}/decide",
                          headers=auth_headers, json={
                              "conclusion": "Recommend first-line immunotherapy",
                              "participants": ["Dr. Wang", "Dr. Li"],
                              "meeting_date": "2024-07-15",
                          })
    assert r.status_code == 200
    data = r.json()
    assert data["status"] == "decided"
    assert data["decision"]["conclusion"] == "Recommend first-line immunotherapy"
    assert len(data["decision"]["participants"]) == 2

    # Verify case now shows as decided
    r = await client.get(f"/api/v1/mdt/cases/{case_id}", headers=auth_headers)
    assert r.status_code == 200
    assert r.json()["status"] == "decided"
    assert len(r.json()["decisions"]) == 1


@pytest.mark.asyncio
async def test_add_decision_minimal(client, auth_headers):
    """Add a decision with only required fields."""
    r = await client.post("/api/v1/mdt/cases", headers=auth_headers, json={
        "title": "Minimal Decision Case",
        "patient_summary": "Test",
    })
    assert r.status_code == 200
    case_id = r.json()["case"]["id"]

    r = await client.post(f"/api/v1/mdt/cases/{case_id}/decide",
                          headers=auth_headers, json={"conclusion": "Continue monitoring"})
    assert r.status_code == 200
    assert r.json()["status"] == "decided"


@pytest.mark.asyncio
async def test_add_decision_case_not_found(client, auth_headers):
    """Add decision to non-existent case returns 404."""
    fake_id = str(uuid.uuid4())
    r = await client.post(f"/api/v1/mdt/cases/{fake_id}/decide",
                          headers=auth_headers, json={"conclusion": "Test"})
    assert r.status_code == 404


@pytest.mark.asyncio
async def test_get_case_no_auth(client):
    """GET /mdt/cases/{id} without auth returns 401."""
    r = await client.get(f"/api/v1/mdt/cases/{uuid.uuid4()}")
    assert r.status_code == 401


@pytest.mark.asyncio
async def test_decide_no_auth(client):
    """POST /mdt/cases/{id}/decide without auth returns 403 (CSRF without Bearer token)."""
    r = await client.post(f"/api/v1/mdt/cases/{uuid.uuid4()}/decide", json={"conclusion": "Test"})
    assert r.status_code == 403


# ─── Evidence tests ─────────────────────────────────────────────────


@pytest.mark.asyncio
async def test_list_evidence(client, auth_headers, db):
    """GET /mdt/cases/{cid}/evidence — create case, add evidence, list → 200."""
    from app.models.literature import GlobalLiterature

    # Seed literature
    lit = GlobalLiterature(pmid=90000991, title="List Evidence Test Article")
    db.add(lit)
    await db.commit()
    await db.refresh(lit)

    # Create case
    r = await client.post("/api/v1/mdt/cases", headers=auth_headers, json={
        "title": "Evidence List Case",
        "patient_summary": "Test list evidence",
    })
    assert r.status_code == 200
    case_id = r.json()["case"]["id"]

    # Add evidence
    r = await client.post(f"/api/v1/mdt/cases/{case_id}/evidence", headers=auth_headers, json={
        "pmid": 90000991,
    })
    assert r.status_code == 200

    # List evidence
    r = await client.get(f"/api/v1/mdt/cases/{case_id}/evidence", headers=auth_headers)
    assert r.status_code == 200
    data = r.json()
    assert data["total"] >= 1
    assert any(e["pmid"] == 90000991 for e in data["items"])


@pytest.mark.asyncio
async def test_add_evidence(client, auth_headers, db):
    """POST /mdt/cases/{cid}/evidence — add evidence with pmid + relevance_note → 200."""
    from app.models.literature import GlobalLiterature

    # Seed literature
    lit = GlobalLiterature(pmid=90000992, title="Add Evidence Test Article")
    db.add(lit)
    await db.commit()
    await db.refresh(lit)

    # Create case
    r = await client.post("/api/v1/mdt/cases", headers=auth_headers, json={
        "title": "Add Evidence Case",
        "patient_summary": "Test add evidence",
    })
    assert r.status_code == 200
    case_id = r.json()["case"]["id"]

    # Add evidence with relevance_note
    r = await client.post(f"/api/v1/mdt/cases/{case_id}/evidence", headers=auth_headers, json={
        "pmid": 90000992,
        "relevance_note": "Key supporting evidence",
    })
    assert r.status_code == 200
    data = r.json()
    assert data["status"] == "added"
    assert data["evidence"]["pmid"] == 90000992
    assert data["evidence"]["relevance_note"] == "Key supporting evidence"


@pytest.mark.asyncio
async def test_delete_evidence(client, auth_headers, db):
    """DELETE /mdt/cases/{cid}/evidence/{eid} — add evidence, delete, verify gone."""
    from app.models.literature import GlobalLiterature

    # Seed literature
    lit = GlobalLiterature(pmid=90000993, title="Delete Evidence Test Article")
    db.add(lit)
    await db.commit()
    await db.refresh(lit)

    # Create case
    r = await client.post("/api/v1/mdt/cases", headers=auth_headers, json={
        "title": "Delete Evidence Case",
        "patient_summary": "Test delete evidence",
    })
    assert r.status_code == 200
    case_id = r.json()["case"]["id"]

    # Add evidence
    r = await client.post(f"/api/v1/mdt/cases/{case_id}/evidence", headers=auth_headers, json={
        "pmid": 90000993,
    })
    assert r.status_code == 200
    evidence_id = r.json()["evidence"]["id"]

    # Delete evidence
    r = await client.delete(f"/api/v1/mdt/cases/{case_id}/evidence/{evidence_id}", headers=auth_headers)
    assert r.status_code == 200
    assert r.json()["status"] == "deleted"

    # Verify gone
    r = await client.get(f"/api/v1/mdt/cases/{case_id}/evidence", headers=auth_headers)
    assert r.status_code == 200
    data = r.json()
    assert data["total"] == 0


@pytest.mark.asyncio
async def test_add_evidence_case_not_found(client, auth_headers):
    """POST /mdt/cases/{cid}/evidence on non-existent case → 404."""
    fake_id = str(uuid.uuid4())
    r = await client.post(f"/api/v1/mdt/cases/{fake_id}/evidence", headers=auth_headers, json={
        "pmid": 90000999,
    })
    assert r.status_code == 404


@pytest.mark.asyncio
async def test_add_evidence_invalid_pmid(client, auth_headers, db):
    """POST /mdt/cases/{cid}/evidence with a PMID not in GlobalLiterature → 404."""
    # Create a valid case first
    r = await client.post("/api/v1/mdt/cases", headers=auth_headers, json={
        "title": "Invalid PMID Case",
        "patient_summary": "Test invalid PMID",
    })
    assert r.status_code == 200
    case_id = r.json()["case"]["id"]

    # Try adding evidence with a PMID that does not exist in GlobalLiterature
    r = await client.post(f"/api/v1/mdt/cases/{case_id}/evidence", headers=auth_headers, json={
        "pmid": 99999999,
    })
    assert r.status_code == 404


# ─── Literature Pack ──────────────────────────────────────────────────


@pytest.mark.asyncio
async def test_literature_pack(client, auth_headers, db):
    """GET /mdt/cases/{cid}/literature-pack — returns auto-suggested articles for the case."""
    from app.models.literature import GlobalLiterature

    # Seed literature matching the case's cancer_type
    lit = GlobalLiterature(
        pmid=90000994, title="Lung Cancer Immunotherapy Advances 2024",
        abstract="Recent advances in immunotherapy for non-small cell lung cancer treatment.",
        cited_by_count=25,
    )
    db.add(lit)

    lit2 = GlobalLiterature(
        pmid=90000995, title="NSCLC Targeted Therapy Review",
        abstract="A comprehensive review of targeted therapies for advanced lung adenocarcinoma.",
        cited_by_count=10,
    )
    db.add(lit2)

    # Non-matching article should not appear
    lit3 = GlobalLiterature(
        pmid=90000996, title="ER-positive Breast Endocrine Therapy",
        abstract="Endocrine therapy for ER-positive breast malignancy outcomes.",
    )
    db.add(lit3)
    await db.commit()

    # Create case with cancer_type matching lung articles
    r = await client.post("/api/v1/mdt/cases", headers=auth_headers, json={
        "title": "Literature Pack Case",
        "patient_summary": "Patient with advanced NSCLC, considering immunotherapy options",
        "cancer_type": "Lung Cancer",
    })
    assert r.status_code == 200
    case_id = r.json()["case"]["id"]

    # Call literature-pack
    r = await client.get(f"/api/v1/mdt/cases/{case_id}/literature-pack", headers=auth_headers)
    assert r.status_code == 200
    data = r.json()
    assert "items" in data
    assert "terms" in data
    assert len(data["terms"]) >= 1
    # Should have matched the lung cancer articles
    pmids = {i["pmid"] for i in data["items"]}
    assert 90000994 in pmids, f"Lung Cancer Immunotherapy article should match, got pmids={pmids}"
    assert 90000995 in pmids, f"NSCLC Targeted Therapy article should match, got pmids={pmids}"
    # The lung articles should rank higher than the breast article due to more specific keyword matches
    lung_rank = next(i for i, x in enumerate(data["items"]) if x["pmid"] == 90000994)
    breast_rank = next((i for i, x in enumerate(data["items"]) if x["pmid"] == 90000996), None)
    if breast_rank is not None:
        assert lung_rank < breast_rank, "Lung cancer article should rank higher than breast cancer article"
    # Each item should have a reason
    assert all(i.get("reason") for i in data["items"])


@pytest.mark.asyncio
async def test_literature_pack_excludes_existing(client, auth_headers, db):
    """Already-added evidence should not appear in literature pack."""
    from app.models.literature import GlobalLiterature

    lit = GlobalLiterature(pmid=90000997, title="Lung Cancer Study 2024", abstract="Lung cancer research.")
    db.add(lit)
    lit2 = GlobalLiterature(pmid=90000998, title="Lung Cancer New Findings", abstract="New lung cancer findings.")
    db.add(lit2)
    await db.commit()

    # Create case
    r = await client.post("/api/v1/mdt/cases", headers=auth_headers, json={
        "title": "Exclude Existing Case",
        "patient_summary": "Lung cancer patient",
        "cancer_type": "Lung",
    })
    assert r.status_code == 200
    case_id = r.json()["case"]["id"]

    # Add 90000997 as evidence
    post_r = await client.post(f"/api/v1/mdt/cases/{case_id}/evidence", headers=auth_headers, json={
        "pmid": 90000997,
    })
    assert post_r.status_code == 200

    # Literature pack should exclude 90000997
    r = await client.get(f"/api/v1/mdt/cases/{case_id}/literature-pack", headers=auth_headers)
    assert r.status_code == 200
    data = r.json()
    pmids = {i["pmid"] for i in data["items"]}
    assert 90000998 in pmids
    assert 90000997 not in pmids


@pytest.mark.asyncio
async def test_literature_pack_no_auth(client):
    """GET /mdt/cases/{cid}/literature-pack without auth returns 401."""
    r = await client.get(f"/api/v1/mdt/cases/{uuid.uuid4()}/literature-pack")
    assert r.status_code == 401


@pytest.mark.asyncio
async def test_literature_pack_not_found(client, auth_headers):
    """GET literature-pack for non-existent case returns 404."""
    fake_id = str(uuid.uuid4())
    r = await client.get(f"/api/v1/mdt/cases/{fake_id}/literature-pack", headers=auth_headers)
    assert r.status_code == 404
