"""Phase 13.2 — Doctor Panel tests."""
from __future__ import annotations

from datetime import datetime, timedelta, timezone

import pytest

from app.events.publisher import get_event_publisher
from app.events.types import HealthcareEventType
from app.tests.conftest import TENANT_A, TENANT_B, tenant_headers
from app.validators.doctor_panel import ensure_visit_session_transition
from app.models.types import VisitSessionAction, VisitSessionStatus
from shared.exceptions import AppError


async def _seed_appointment(client):
    headers = tenant_headers(TENANT_A)
    clinic = await client.post(
        "/api/v1/clinics",
        headers=headers,
        json={"code": "CLN132", "name": "Visit Clinic", "status": "active"},
    )
    clinic_id = clinic.json()["id"]
    doctor = await client.post(
        "/api/v1/doctors",
        headers=headers,
        json={
            "user_id": "doc-132",
            "clinic_id": clinic_id,
            "code": "DOC132",
            "display_name": "Dr Visit",
        },
    )
    doctor_id = doctor.json()["id"]
    patient = await client.post(
        "/api/v1/patients",
        headers=headers,
        json={
            "user_id": "pat-132",
            "code": "PAT132",
            "display_name": "Patient Visit",
        },
    )
    patient_id = patient.json()["id"]
    start = datetime(2026, 9, 1, 10, 0, tzinfo=timezone.utc)
    end = start + timedelta(minutes=30)
    appt = await client.post(
        "/api/v1/appointments",
        headers=headers,
        json={
            "clinic_id": clinic_id,
            "doctor_id": doctor_id,
            "patient_id": patient_id,
            "code": "APT132",
            "scheduled_start": start.isoformat(),
            "scheduled_end": end.isoformat(),
        },
    )
    assert appt.status_code == 201
    aid = appt.json()["id"]
    version = appt.json()["version"]
    confirmed = await client.post(
        f"/api/v1/appointments/{aid}/confirm",
        headers=headers,
        json={"version": version},
    )
    assert confirmed.status_code == 200
    return clinic_id, doctor_id, patient_id, aid, confirmed.json()["version"]


def test_visit_session_transition_unit():
    ensure_visit_session_transition(
        action=VisitSessionAction.START, current=VisitSessionStatus.QUEUED
    )
    with pytest.raises(AppError) as exc:
        ensure_visit_session_transition(
            action=VisitSessionAction.FINISH, current=VisitSessionStatus.QUEUED
        )
    assert exc.value.error_code == "invalid_visit_session_transition"


@pytest.mark.asyncio
async def test_visit_session_lifecycle_completes_appointment(client):
    clinic_id, doctor_id, patient_id, appt_id, appt_version = await _seed_appointment(client)
    headers = tenant_headers(TENANT_A)

    session = await client.post(
        "/api/v1/visit-sessions",
        headers=headers,
        json={
            "clinic_id": clinic_id,
            "doctor_id": doctor_id,
            "patient_id": patient_id,
            "appointment_id": appt_id,
            "code": "VS1",
            "queue_position": 10,
        },
    )
    assert session.status_code == 201, session.text
    vs = session.json()
    assert vs["status"] == "queued"
    vid = vs["id"]
    version = vs["version"]

    started = await client.post(
        f"/api/v1/visit-sessions/{vid}/start",
        headers=headers,
        json={"version": version},
    )
    assert started.status_code == 200
    assert started.json()["status"] == "in_progress"
    version = started.json()["version"]

    appt = await client.get(f"/api/v1/appointments/{appt_id}", headers=headers)
    assert appt.json()["status"] == "checked_in"

    finished = await client.post(
        f"/api/v1/visit-sessions/{vid}/finish",
        headers=headers,
        json={"version": version},
    )
    assert finished.status_code == 200
    assert finished.json()["status"] == "completed"

    appt = await client.get(f"/api/v1/appointments/{appt_id}", headers=headers)
    assert appt.json()["status"] == "completed"

    events = {e.event_type for e in get_event_publisher().published}
    assert HealthcareEventType.VISIT_SESSION_CREATED.value in events
    assert HealthcareEventType.VISIT_SESSION_STARTED.value in events
    assert HealthcareEventType.VISIT_SESSION_FINISHED.value in events
    assert HealthcareEventType.APPOINTMENT_COMPLETED.value in events


@pytest.mark.asyncio
async def test_doctor_dashboard_and_queue(client):
    clinic_id, doctor_id, patient_id, appt_id, _ = await _seed_appointment(client)
    headers = tenant_headers(TENANT_A)
    await client.post(
        "/api/v1/visit-sessions",
        headers=headers,
        json={
            "clinic_id": clinic_id,
            "doctor_id": doctor_id,
            "patient_id": patient_id,
            "appointment_id": appt_id,
            "code": "VS-Q",
        },
    )

    dashboard = await client.get(
        "/api/v1/doctor-panel/dashboard",
        headers=headers,
        params={"doctor_id": doctor_id},
    )
    assert dashboard.status_code == 200
    assert dashboard.json()["queued_count"] >= 1

    queue = await client.get(
        "/api/v1/doctor-panel/queue",
        headers=headers,
        params={"doctor_id": doctor_id},
    )
    assert queue.status_code == 200
    assert len(queue.json()["items"]) >= 1


@pytest.mark.asyncio
async def test_visit_note_and_tenant_isolation(client):
    clinic_id, doctor_id, patient_id, appt_id, _ = await _seed_appointment(client)
    headers = tenant_headers(TENANT_A)
    session = await client.post(
        "/api/v1/visit-sessions",
        headers=headers,
        json={
            "clinic_id": clinic_id,
            "doctor_id": doctor_id,
            "patient_id": patient_id,
            "appointment_id": appt_id,
            "code": "VS-N",
        },
    )
    vid = session.json()["id"]

    note = await client.post(
        "/api/v1/visit-notes",
        headers=headers,
        json={
            "visit_session_id": vid,
            "doctor_id": doctor_id,
            "code": "VN1",
            "title": "Initial assessment",
            "body": "Patient stable",
            "storage_file_ref": "storage://file-1",
        },
    )
    assert note.status_code == 201

    other = await client.get(
        f"/api/v1/visit-sessions/{vid}",
        headers=tenant_headers(TENANT_B),
    )
    assert other.status_code == 404


@pytest.mark.asyncio
async def test_phase_132_capabilities(client):
    caps = await client.get("/capabilities")
    assert caps.json()["features"]["visits"] is True
    assert caps.json()["features"]["doctor_panel"] is True
