"""Case and ICD code models."""

from __future__ import annotations

import datetime as dt
from typing import Optional

from sqlalchemy import (
    Boolean,
    CheckConstraint,
    Date,
    DateTime,
    ForeignKey,
    Index,
    Integer,
    SmallInteger,
    String,
    Text,
    UniqueConstraint,
    func,
    text,
)
from sqlalchemy.orm import Mapped, mapped_column, relationship

from app.database import Base


class Case(Base):
    __tablename__ = "cases"

    id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
    fall_id: Mapped[Optional[str]] = mapped_column(String(100), nullable=True)
    crm_ticket_id: Mapped[Optional[str]] = mapped_column(String(20), nullable=True)
    jahr: Mapped[int] = mapped_column(SmallInteger, nullable=False)
    kw: Mapped[int] = mapped_column(SmallInteger, nullable=False)
    datum: Mapped[dt.date] = mapped_column(Date, nullable=False)
    anrede: Mapped[Optional[str]] = mapped_column(String(20), nullable=True)
    vorname: Mapped[Optional[str]] = mapped_column(String(100), nullable=True)
    nachname: Mapped[str] = mapped_column(String(100), nullable=False)
    geburtsdatum: Mapped[Optional[dt.date]] = mapped_column(Date, nullable=True)
    kvnr: Mapped[Optional[str]] = mapped_column(String(20), nullable=True)
    versicherung: Mapped[str] = mapped_column(
        String(50), nullable=False, server_default="DAK"
    )
    icd: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
    fallgruppe: Mapped[str] = mapped_column(String(20), nullable=False)
    strasse: Mapped[Optional[str]] = mapped_column(String(255), nullable=True)
    plz: Mapped[Optional[str]] = mapped_column(String(10), nullable=True)
    ort: Mapped[Optional[str]] = mapped_column(String(100), nullable=True)
    email: Mapped[Optional[str]] = mapped_column(String(255), nullable=True)
    ansprechpartner: Mapped[Optional[str]] = mapped_column(String(200), nullable=True)
    telefonnummer: Mapped[Optional[str]] = mapped_column(String(50), nullable=True)
    mobiltelefon: Mapped[Optional[str]] = mapped_column(String(50), nullable=True)
    email2: Mapped[Optional[str]] = mapped_column(String(255), nullable=True)
    telefon2: Mapped[Optional[str]] = mapped_column(String(50), nullable=True)
    unterlagen: Mapped[bool] = mapped_column(
        Boolean, nullable=False, server_default="0"
    )
    unterlagen_verschickt: Mapped[Optional[dt.date]] = mapped_column(
        Date, nullable=True
    )
    erhalten: Mapped[Optional[bool]] = mapped_column(Boolean, nullable=True)
    unterlagen_erhalten: Mapped[Optional[dt.date]] = mapped_column(
        Date, nullable=True
    )
    unterlagen_an_gutachter: Mapped[Optional[dt.date]] = mapped_column(
        Date, nullable=True
    )
    gutachten: Mapped[bool] = mapped_column(
        Boolean, nullable=False, server_default="0"
    )
    gutachter: Mapped[Optional[str]] = mapped_column(String(100), nullable=True)
    gutachten_erstellt: Mapped[Optional[dt.date]] = mapped_column(
        Date, nullable=True
    )
    gutachten_versendet: Mapped[Optional[dt.date]] = mapped_column(
        Date, nullable=True
    )
    schweigepflicht: Mapped[bool] = mapped_column(
        Boolean, nullable=False, server_default="0"
    )
    ablehnung: Mapped[bool] = mapped_column(
        Boolean, nullable=False, server_default="0"
    )
    abbruch: Mapped[bool] = mapped_column(
        Boolean, nullable=False, server_default="0"
    )
    abbruch_datum: Mapped[Optional[dt.date]] = mapped_column(Date, nullable=True)
    gutachten_typ: Mapped[Optional[str]] = mapped_column(String(20), nullable=True)
    therapieaenderung: Mapped[Optional[str]] = mapped_column(String(5), nullable=True)
    ta_diagnosekorrektur: Mapped[bool] = mapped_column(
        Boolean, nullable=False, server_default="0"
    )
    ta_unterversorgung: Mapped[bool] = mapped_column(
        Boolean, nullable=False, server_default="0"
    )
    ta_uebertherapie: Mapped[bool] = mapped_column(
        Boolean, nullable=False, server_default="0"
    )
    kurzbeschreibung: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
    fragestellung: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
    kommentar: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
    sonstiges: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
    abgerechnet: Mapped[bool] = mapped_column(
        Boolean, nullable=False, server_default="0"
    )
    abrechnung_datum: Mapped[Optional[dt.date]] = mapped_column(Date, nullable=True)
    import_source: Mapped[Optional[str]] = mapped_column(String(255), nullable=True)
    imported_at: Mapped[dt.datetime] = mapped_column(
        DateTime, nullable=False, server_default=func.now()
    )
    updated_at: Mapped[dt.datetime] = mapped_column(
        DateTime,
        nullable=False,
        server_default=func.now(),
        onupdate=func.now(),
    )
    updated_by: Mapped[Optional[int]] = mapped_column(
        Integer, ForeignKey("users.id"), nullable=True
    )
    icd_entered_by: Mapped[Optional[int]] = mapped_column(
        Integer, ForeignKey("users.id"), nullable=True
    )
    icd_entered_at: Mapped[Optional[dt.datetime]] = mapped_column(
        DateTime, nullable=True
    )
    coding_completed_by: Mapped[Optional[int]] = mapped_column(
        Integer, ForeignKey("users.id"), nullable=True
    )
    coding_completed_at: Mapped[Optional[dt.datetime]] = mapped_column(
        DateTime, nullable=True
    )

    # Relationships
    icd_codes: Mapped[list[CaseICDCode]] = relationship(
        back_populates="case", cascade="all, delete-orphan"
    )
    updated_by_user: Mapped[Optional["User"]] = relationship(
        foreign_keys=[updated_by]
    )
    icd_entered_by_user: Mapped[Optional["User"]] = relationship(
        foreign_keys=[icd_entered_by]
    )
    coding_completed_by_user: Mapped[Optional["User"]] = relationship(
        foreign_keys=[coding_completed_by]
    )

    __table_args__ = (
        UniqueConstraint("fall_id", name="uk_fall_id"),
        Index("idx_jahr_kw", "jahr", "kw"),
        Index("idx_kvnr", "kvnr"),
        Index("idx_fallgruppe", "fallgruppe"),
        Index("idx_datum", "datum"),
        Index("idx_nachname_vorname", "nachname", "vorname"),
        # Note: idx_pending_icd uses a functional index on left(icd, 20).
        # We use text() for the expression column.
        Index("idx_pending_icd", "jahr", "kw", "fallgruppe", text("left(icd, 20)")),
        Index("idx_pending_coding", "gutachten", "gutachten_typ"),
        CheckConstraint(
            "fallgruppe IN ('onko','kardio','intensiv','galle','sd')",
            name="chk_fallgruppe",
        ),
        CheckConstraint(
            "gutachten_typ IS NULL OR gutachten_typ IN ('Bestätigung','Alternative')",
            name="chk_gutachten_typ",
        ),
        CheckConstraint(
            "therapieaenderung IS NULL OR therapieaenderung IN ('Ja','Nein')",
            name="chk_ta",
        ),
    )


class CaseICDCode(Base):
    __tablename__ = "case_icd_codes"

    id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
    case_id: Mapped[int] = mapped_column(
        Integer,
        ForeignKey("cases.id", ondelete="CASCADE"),
        nullable=False,
    )
    icd_code: Mapped[str] = mapped_column(String(20), nullable=False)
    icd_hauptgruppe: Mapped[Optional[str]] = mapped_column(String(10), nullable=True)
    created_at: Mapped[dt.datetime] = mapped_column(
        DateTime, nullable=False, server_default=func.now()
    )

    # Relationships
    case: Mapped[Case] = relationship(back_populates="icd_codes")

    __table_args__ = (
        Index("idx_icd_case", "case_id"),
        Index("idx_icd_code", "icd_code"),
        Index("idx_icd_haupt", "icd_hauptgruppe"),
    )
