from datetime import datetime

from app.extensions import db
from app.models import CONDITION_CATEGORIES, Document, MedicalEvent, Summary
from app.processing import llm
from app.processing.entities import (
    get_or_create_doctor,
    get_or_create_health_entity,
    get_or_create_medication,
)


def _parse_event_date(value):
    if not value:
        return None
    try:
        return datetime.strptime(value, "%Y-%m-%d").date()
    except (ValueError, TypeError):
        return None


def process_document(document: Document) -> None:
    """Extracts structured medical events from one document and stores them.

    Marks the document as done/error but does not commit — the caller controls
    the transaction so a batch of documents can be processed with one flush pattern.
    """
    document.status = Document.STATUS_PROCESSING
    db.session.flush()

    try:
        result = llm.extract_medical_data(document.storage_path, document.mime_type)
    except Exception as exc:  # noqa: BLE001 - any failure marks the document as errored
        document.status = Document.STATUS_ERROR
        document.error_message = str(exc)[:2000]
        document.processed_at = datetime.utcnow()
        return

    patient = document.patient

    for event in result.get("events", []):
        event_date = _parse_event_date(event.get("event_date"))
        condition_category = event.get("condition_category")
        if condition_category not in CONDITION_CATEGORIES:
            condition_category = None

        doctor = get_or_create_doctor(
            event.get("doctor_name"), license_number=event.get("doctor_license")
        )
        health_entity = get_or_create_health_entity(event.get("health_entity_name"))
        medication = None
        if event.get("event_type") == "medication":
            medication = get_or_create_medication(
                event.get("medication_generic_name"),
                brand_name=event.get("medication_brand_name"),
                manufacturer_lab=event.get("medication_manufacturer"),
            )

        if doctor and health_entity and not doctor.health_entity_id:
            doctor.health_entity_id = health_entity.id

        medical_event = MedicalEvent(
            patient_id=document.patient_id,
            document_id=document.id,
            event_type=event.get("event_type") or "other",
            description=event.get("description") or "",
            event_date=event_date,
            condition_category=condition_category,
            patient_age_at_event=patient.age_at(event_date) if event_date else patient.age(),
            doctor=doctor,
            health_entity=health_entity,
            medication=medication,
        )
        medical_event.structured_data = event
        db.session.add(medical_event)

    document.status = Document.STATUS_DONE
    document.processed_at = datetime.utcnow()


def regenerate_summary(patient) -> Summary:
    """Regenerates the patient's clinical summary from all their medical events so far."""
    events = [
        {
            "event_type": e.event_type,
            "description": e.description,
            "event_date": e.event_date.isoformat() if e.event_date else None,
        }
        for e in patient.medical_events
    ]

    content = llm.generate_summary(patient.full_name, patient.age(), events)

    last = patient.latest_summary()
    next_version = (last.version + 1) if last else 1

    summary = Summary(patient_id=patient.id, content=content, version=next_version)
    db.session.add(summary)
    return summary
