"""Medical record aggregates — Phase 13.5."""
from __future__ import annotations

import uuid
from datetime import datetime

from sqlalchemy import DateTime, Index, String, Text, UniqueConstraint
from sqlalchemy.orm import Mapped, mapped_column
from sqlalchemy.types import JSON

from app.core.database import Base
from app.models.base import (
    ActorAuditMixin,
    OptimisticLockMixin,
    SoftDeleteMixin,
    TenantMixin,
    TimestampMixin,
    UUIDPrimaryKeyMixin,
)
from app.models.types import EncounterStatus, GUID


class MedicalRecord(
    Base,
    UUIDPrimaryKeyMixin,
    TenantMixin,
    TimestampMixin,
    SoftDeleteMixin,
    ActorAuditMixin,
    OptimisticLockMixin,
):
    __tablename__ = "medical_records"

    clinic_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    patient_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    code: Mapped[str] = mapped_column(String(50), nullable=False)
    access_policy: Mapped[dict | None] = mapped_column(JSON, nullable=True)
    metadata_json: Mapped[dict | None] = mapped_column(JSON, nullable=True)

    __table_args__ = (
        UniqueConstraint("tenant_id", "code", name="uq_medical_records_tenant_code"),
        Index("ix_medical_records_patient", "tenant_id", "patient_id"),
    )


class Encounter(
    Base,
    UUIDPrimaryKeyMixin,
    TenantMixin,
    TimestampMixin,
    SoftDeleteMixin,
    ActorAuditMixin,
    OptimisticLockMixin,
):
    __tablename__ = "encounters"

    medical_record_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    visit_session_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    appointment_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    doctor_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    code: Mapped[str] = mapped_column(String(50), nullable=False)
    status: Mapped[EncounterStatus] = mapped_column(
        default=EncounterStatus.DRAFT, nullable=False
    )
    chief_complaint: Mapped[str | None] = mapped_column(Text, nullable=True)
    clinical_summary: Mapped[str | None] = mapped_column(Text, nullable=True)
    finalized_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
    addendum: Mapped[str | None] = mapped_column(Text, nullable=True)
    metadata_json: Mapped[dict | None] = mapped_column(JSON, nullable=True)

    __table_args__ = (
        UniqueConstraint("tenant_id", "code", name="uq_encounters_tenant_code"),
        Index("ix_encounters_record", "tenant_id", "medical_record_id"),
    )


class Condition(
    Base,
    UUIDPrimaryKeyMixin,
    TenantMixin,
    TimestampMixin,
    SoftDeleteMixin,
    ActorAuditMixin,
):
    __tablename__ = "conditions"

    medical_record_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    code: Mapped[str] = mapped_column(String(50), nullable=False)
    display: Mapped[str] = mapped_column(String(255), nullable=False)
    clinical_status: Mapped[str | None] = mapped_column(String(50), nullable=True)
    metadata_json: Mapped[dict | None] = mapped_column(JSON, nullable=True)

    __table_args__ = (
        UniqueConstraint("tenant_id", "code", name="uq_conditions_tenant_code"),
        Index("ix_conditions_record", "tenant_id", "medical_record_id"),
    )


class Allergy(
    Base,
    UUIDPrimaryKeyMixin,
    TenantMixin,
    TimestampMixin,
    SoftDeleteMixin,
    ActorAuditMixin,
):
    __tablename__ = "allergies"

    medical_record_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    code: Mapped[str] = mapped_column(String(50), nullable=False)
    substance: Mapped[str] = mapped_column(String(255), nullable=False)
    severity: Mapped[str | None] = mapped_column(String(50), nullable=True)
    metadata_json: Mapped[dict | None] = mapped_column(JSON, nullable=True)

    __table_args__ = (
        UniqueConstraint("tenant_id", "code", name="uq_allergies_tenant_code"),
        Index("ix_allergies_record", "tenant_id", "medical_record_id"),
    )


class MedicationStatement(
    Base,
    UUIDPrimaryKeyMixin,
    TenantMixin,
    TimestampMixin,
    SoftDeleteMixin,
    ActorAuditMixin,
):
    __tablename__ = "medication_statements"

    medical_record_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    code: Mapped[str] = mapped_column(String(50), nullable=False)
    medication_code: Mapped[str] = mapped_column(String(100), nullable=False)
    display: Mapped[str] = mapped_column(String(255), nullable=False)
    dosage: Mapped[str | None] = mapped_column(String(100), nullable=True)
    metadata_json: Mapped[dict | None] = mapped_column(JSON, nullable=True)

    __table_args__ = (
        UniqueConstraint("tenant_id", "code", name="uq_medication_statements_tenant_code"),
        Index("ix_medication_statements_record", "tenant_id", "medical_record_id"),
    )


class ImmunizationRecord(
    Base,
    UUIDPrimaryKeyMixin,
    TenantMixin,
    TimestampMixin,
    SoftDeleteMixin,
    ActorAuditMixin,
):
    __tablename__ = "immunization_records"

    medical_record_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    code: Mapped[str] = mapped_column(String(50), nullable=False)
    vaccine_code: Mapped[str] = mapped_column(String(100), nullable=False)
    administered_on: Mapped[str | None] = mapped_column(String(32), nullable=True)
    storage_file_ref: Mapped[str | None] = mapped_column(String(255), nullable=True)
    metadata_json: Mapped[dict | None] = mapped_column(JSON, nullable=True)

    __table_args__ = (
        UniqueConstraint("tenant_id", "code", name="uq_immunization_records_tenant_code"),
        Index("ix_immunization_records_record", "tenant_id", "medical_record_id"),
    )


class MedicalRecordAccessLog(Base, UUIDPrimaryKeyMixin, TenantMixin, TimestampMixin):
    __tablename__ = "medical_record_access_logs"

    medical_record_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    actor_user_id: Mapped[str] = mapped_column(String(100), nullable=False)
    action: Mapped[str] = mapped_column(String(50), nullable=False)
    reason: Mapped[str | None] = mapped_column(String(500), nullable=True)
    metadata_json: Mapped[dict | None] = mapped_column(JSON, nullable=True)

    __table_args__ = (
        Index("ix_medical_record_access_logs_record", "tenant_id", "medical_record_id"),
    )
