"""
Modelli Archival – versamenti verso conservatore AgID.
"""

import uuid
from datetime import date, datetime

from sqlalchemy import (
    CHAR,
    DateTime,
    Enum,
    ForeignKey,
    Index,
    Integer,
    String,
    Text,
    func,
)
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.orm import Mapped, mapped_column

from app.database import Base

ArchivalStatus = Enum(
    "pending", "building_sip", "uploading", "uploaded",
    "confirmed", "rejected", "failed",
    name="archival_status",
    create_type=False,
)


class ArchivalBatch(Base):
    __tablename__ = "archival_batches"

    id: Mapped[uuid.UUID] = mapped_column(
        UUID(as_uuid=True), primary_key=True, default=uuid.uuid4
    )
    tenant_id: Mapped[uuid.UUID] = mapped_column(
        UUID(as_uuid=True), ForeignKey("tenants.id", ondelete="CASCADE"), nullable=False
    )
    conservatore_id: Mapped[str] = mapped_column(String(100), nullable=False)
    status: Mapped[str] = mapped_column(ArchivalStatus, nullable=False, default="pending")

    sip_path: Mapped[str | None] = mapped_column(Text, nullable=True)
    sip_checksum: Mapped[str | None] = mapped_column(CHAR(64), nullable=True)

    versamento_id: Mapped[str | None] = mapped_column(Text, nullable=True)
    rdv_received_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
    rdv_path: Mapped[str | None] = mapped_column(Text, nullable=True)
    rdv_checksum: Mapped[str | None] = mapped_column(CHAR(64), nullable=True)

    attempt_count: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
    max_attempts: Mapped[int] = mapped_column(Integer, nullable=False, default=3)
    next_retry_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
    last_error: Mapped[str | None] = mapped_column(Text, nullable=True)

    period_from: Mapped[date] = mapped_column(nullable=False)
    period_to: Mapped[date] = mapped_column(nullable=False)

    created_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True), nullable=False, server_default=func.now()
    )
    updated_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True), nullable=False, server_default=func.now(), onupdate=func.now()
    )

    __table_args__ = (
        Index("idx_archival_tenant", "tenant_id"),
        Index("idx_archival_status", "status", "next_retry_at"),
    )


class ArchivalBatchMessage(Base):
    __tablename__ = "archival_batch_messages"

    batch_id: Mapped[uuid.UUID] = mapped_column(
        UUID(as_uuid=True),
        ForeignKey("archival_batches.id", ondelete="CASCADE"),
        primary_key=True,
    )
    message_id: Mapped[uuid.UUID] = mapped_column(
        UUID(as_uuid=True),
        ForeignKey("messages.id", ondelete="CASCADE"),
        primary_key=True,
    )


class ArchivalDip(Base):
    __tablename__ = "archival_dips"

    id: Mapped[uuid.UUID] = mapped_column(
        UUID(as_uuid=True), primary_key=True, default=uuid.uuid4
    )
    tenant_id: Mapped[uuid.UUID] = mapped_column(
        UUID(as_uuid=True), ForeignKey("tenants.id", ondelete="CASCADE"), nullable=False
    )
    batch_id: Mapped[uuid.UUID | None] = mapped_column(
        UUID(as_uuid=True), ForeignKey("archival_batches.id"), nullable=True
    )
    requested_by: Mapped[uuid.UUID | None] = mapped_column(
        UUID(as_uuid=True), ForeignKey("users.id"), nullable=True
    )
    dip_path: Mapped[str | None] = mapped_column(Text, nullable=True)
    status: Mapped[str] = mapped_column(String(50), nullable=False, default="requested")
    requested_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True), nullable=False, server_default=func.now()
    )
    received_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
