"""
Diagnostic report model.

Tables in this file:
  report — medical diagnostic reports generated for visit orders

Report Lifecycle & Architecture
─────────────────────────────────
A Report represents the official diagnostic findings generated for a
VisitOrder. It supports an end-to-end verification and amendment workflow:

  1. Draft:
     Created when test results have been entered for an order.
     status = DRAFT

  2. Verification:
     Submitted for pathologist or radiologist review.
     status = PENDING_VERIFICATION
     - Pathologist approves: status = VERIFIED, verified_by and verified_at set.
     - Pathologist rejects: status = REJECTED, verification_reason recorded.

  3. Release:
     Once verified, the report is released to the patient.
     status = RELEASED, released_at set.
     Triggers PDF generation (ReportLab) -> file_url updated with S3/MinIO key.
     Client receives SMS/email with a 72-hour secure link to view/download.

Versioning & Audit Trail
─────────────────────────
Medical reports are legal documents. Once released, they can never be modified in-place.
If a correction or re-run is required:
  - A new Report record is created with incremented version (version = 2, 3...).
  - previous_report_id points to the prior Report version.
  - The previous report remains in the database for complete forensic auditability.
  - UniqueConstraint("order_id", "version") guarantees no version collisions per order.

Soft Delete Decisions
─────────────────────
  Report → YES (SoftDeleteMixin): medical diagnostic records must never be hard-deleted
           during standard application operations.

Lab Scoping
───────────
  Report → NO (scoped indirectly via order_id -> visit_order.lab_id).
"""

import datetime
import enum
import uuid

import sqlalchemy as sa
from sqlalchemy import (
    ForeignKey,
    Integer,
    String,
    Text,
    UniqueConstraint,
)
from sqlalchemy.dialects.postgresql import JSONB, TIMESTAMP, UUID
from sqlalchemy.orm import Mapped, mapped_column, relationship

from app.models.base import (
    Base,
    SoftDeleteMixin,
    TimestampMixin,
    UUIDPrimaryKeyMixin,
)
from app.models.test import CategoryModality, CategoryModalityType

# ── Enums ──────────────────────────────────────────────────────────────────────


class ReportStatus(enum.StrEnum):
    """
    Lifecycle states for diagnostic reports.

    draft                -> initial draft generated from completed test results
    pending_verification -> awaiting review and sign-off by pathologist/doctor
    verified             -> approved and electronically signed by medical authority
    released             -> published and made available to the patient
    rejected             -> rejected during verification review (requires amendment)
    """

    DRAFT = "draft"
    PENDING_VERIFICATION = "pending_verification"
    VERIFIED = "verified"
    RELEASED = "released"
    REJECTED = "rejected"


ReportStatusType = sa.Enum(
    ReportStatus,
    name="report_status",
    native_enum=True,
    create_constraint=True,
    values_callable=lambda obj: [e.value for e in obj],
)


# ── Models ─────────────────────────────────────────────────────────────────────


class Report(UUIDPrimaryKeyMixin, TimestampMixin, SoftDeleteMixin, Base):
    """
    Diagnostic lab report generated for a visit order.

    Supports clinical verification workflows, immutable versioning for amendments,
    and secure PDF storage linking.
    """

    __tablename__ = "report"
    __table_args__ = (
        UniqueConstraint("order_id", "modality", "version", name="uq_report_order_version_modality"),
        UniqueConstraint("public_token", name="uq_report_public_token"),
    )

    # ── Foreign Keys ───────────────────────────────────────────────────────────
    order_id: Mapped[uuid.UUID] = mapped_column(
        UUID(as_uuid=True),
        ForeignKey("visit_order.id", ondelete="RESTRICT"),
        nullable=False,
        index=True,
        comment="FK → visit_order.id. Scopes the report to the order and lab branch.",
    )
    verified_by: Mapped[uuid.UUID | None] = mapped_column(
        UUID(as_uuid=True),
        ForeignKey("user.id", ondelete="SET NULL"),
        nullable=True,
        index=True,
        comment="FK → user.id. Pathologist/doctor who verified and signed this report.",
    )
    previous_report_id: Mapped[uuid.UUID | None] = mapped_column(
        UUID(as_uuid=True),
        ForeignKey("report.id", ondelete="SET NULL"),
        nullable=True,
        index=True,
        comment="FK → report.id. Points to prior version if this report was amended or re-run.",
    )

    # ── Attributes ─────────────────────────────────────────────────────────────
    modality: Mapped[CategoryModality] = mapped_column(
        CategoryModalityType,
        nullable=False,
        default=CategoryModality.PATHOLOGY,
        server_default="pathology",
        comment="Discipline side: pathology (specimen lab) or imaging (radiology). One report per side.",
    )
    version: Mapped[int] = mapped_column(
        Integer,
        nullable=False,
        default=1,
        server_default="1",
        comment="Incremental version number for this order-side's reports (1, 2, ...)",
    )
    status: Mapped[ReportStatus] = mapped_column(
        ReportStatusType,
        nullable=False,
        default=ReportStatus.DRAFT,
        server_default="draft",
        index=True,
        comment="Report verification and release lifecycle status",
    )
    verification_reason: Mapped[str | None] = mapped_column(
        Text,
        nullable=True,
        comment="Clinical remarks, verification notes, or rejection rationale",
    )
    verified_at: Mapped[datetime.datetime | None] = mapped_column(
        TIMESTAMP(timezone=True),
        nullable=True,
        comment="Timestamp when the report was verified by medical authority (TIMESTAMPTZ)",
    )
    released_at: Mapped[datetime.datetime | None] = mapped_column(
        TIMESTAMP(timezone=True),
        nullable=True,
        comment="Timestamp when the report was released to patient (TIMESTAMPTZ)",
    )
    file_url: Mapped[str | None] = mapped_column(
        String(500),
        nullable=True,
        comment="Object storage key/URI for the generated PDF report file",
    )
    result_data: Mapped[dict[str, object] | None] = mapped_column(
        JSONB,
        nullable=True,
        comment="Structured test analyte observations, values, reference intervals, and abnormal flags",
    )
    notes: Mapped[str | None] = mapped_column(
        Text,
        nullable=True,
        comment="Clinical remarks or pathology interpretation notes included in the report",
    )
    public_token: Mapped[str | None] = mapped_column(
        String(64),
        nullable=True,
        index=True,
        comment="Durable no-login capability token for the printed QR code (set at release)",
    )

    # ── Relationships ──────────────────────────────────────────────────────────
    order: Mapped["VisitOrder"] = relationship(  # type: ignore[name-defined]
        "VisitOrder",
        foreign_keys="[Report.order_id]",
        lazy="selectin",
    )
    verifier: Mapped["User | None"] = relationship(  # type: ignore[name-defined]
        "User",
        foreign_keys="[Report.verified_by]",
        lazy="selectin",
    )
    previous_report: Mapped["Report | None"] = relationship(
        "Report",
        foreign_keys="[Report.previous_report_id]",
        remote_side="[Report.id]",
        lazy="noload",
    )
    amendments: Mapped[list["Report"]] = relationship(
        "Report",
        foreign_keys="[Report.previous_report_id]",
        lazy="noload",
    )

    def __repr__(self) -> str:
        return (
            f"<Report id={self.id!s:.8} "
            f"order_id={self.order_id!s:.8} "
            f"version={self.version} "
            f"status={self.status.value!r}>"
        )
