"""
Re-export dei modelli SQLAlchemy dal backend.

Il worker usa gli stessi modelli ORM del backend per leggere/scrivere nel DB.
Importa da una base comune tramite il package condiviso.

Nota: i modelli sono definiti nel backend. Il worker li ridefinisce qui
come classi identiche (stessa struttura) per non creare dipendenza circolare.
Tuttavia, poiché i due container condividono lo stesso DB PostgreSQL,
utilizziamo i modelli del backend ricopiando solo le parti necessarie.
"""

# I modelli completi sono già in backend/app/models/.
# Il worker li importa dalla propria copia locale per evitare
# una dipendenza del package worker → backend.
# In un monorepo reale si userebbe un shared/ package.

import uuid
from datetime import datetime

from sqlalchemy import (
    ARRAY, BigInteger, Boolean, DateTime, Enum, ForeignKey,
    Integer, String, Text, func,
)
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship


class Base(DeclarativeBase):
    pass


MailboxStatus = Enum(
    "active", "paused", "error", "deleted",
    name="mailbox_status", create_type=False,
)

PecDirection = Enum("inbound", "outbound", name="pec_direction", create_type=False)
PecState = Enum(
    "draft", "queued", "sent", "accepted", "delivered", "anomaly", "failed", "received",
    name="pec_state", create_type=False,
)
PecMsgType = Enum(
    "posta_certificata", "accettazione", "non_accettazione", "presa_in_carico",
    "avvenuta_consegna", "mancata_consegna", "errore_consegna",
    "preavviso_mancata_consegna", "rilevazione_virus", "unknown",
    name="pec_msg_type", create_type=False,
)


class Mailbox(Base):
    __tablename__ = "mailboxes"

    id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True)
    tenant_id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), nullable=False)
    email_address: Mapped[str] = mapped_column(String(255), nullable=False)
    display_name: Mapped[str | None] = mapped_column(String(255), nullable=True)
    provider: Mapped[str | None] = mapped_column(String(100), nullable=True)

    imap_host_enc: Mapped[str] = mapped_column(Text, nullable=False)
    imap_port_enc: Mapped[str] = mapped_column(Text, nullable=False)
    imap_user_enc: Mapped[str] = mapped_column(Text, nullable=False)
    imap_pass_enc: Mapped[str] = mapped_column(Text, nullable=False)
    imap_use_ssl: Mapped[bool] = mapped_column(Boolean, nullable=False, default=True)

    smtp_host_enc: Mapped[str] = mapped_column(Text, nullable=False)
    smtp_port_enc: Mapped[str] = mapped_column(Text, nullable=False)
    smtp_user_enc: Mapped[str] = mapped_column(Text, nullable=False)
    smtp_pass_enc: Mapped[str] = mapped_column(Text, nullable=False)
    smtp_use_tls: Mapped[bool] = mapped_column(Boolean, nullable=False, default=True)

    status: Mapped[str] = mapped_column(MailboxStatus, nullable=False, default="active")
    last_sync_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
    last_sync_uid: Mapped[int | None] = mapped_column(BigInteger, nullable=True)
    sync_error_msg: Mapped[str | None] = mapped_column(Text, nullable=True)
    sync_error_count: Mapped[int] = mapped_column(Integer, nullable=False, default=0)

    created_by: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True), nullable=True)
    created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
    updated_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True), server_default=func.now(), onupdate=func.now()
    )


class Message(Base):
    __tablename__ = "messages"

    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), nullable=False)
    mailbox_id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), nullable=False)

    message_id_header: Mapped[str | None] = mapped_column(Text, nullable=True)
    imap_uid: Mapped[int | None] = mapped_column(BigInteger, nullable=True)
    imap_folder: Mapped[str] = mapped_column(String(255), nullable=False, default="INBOX")

    direction: Mapped[str] = mapped_column(PecDirection, nullable=False)
    pec_type: Mapped[str] = mapped_column(PecMsgType, nullable=False, default="posta_certificata")
    state: Mapped[str] = mapped_column(PecState, nullable=False)

    subject: Mapped[str | None] = mapped_column(Text, nullable=True)
    from_address: Mapped[str | None] = mapped_column(String(255), nullable=True)
    to_addresses: Mapped[list[str] | None] = mapped_column(ARRAY(Text), nullable=True)
    cc_addresses: Mapped[list[str] | None] = mapped_column(ARRAY(Text), nullable=True)
    sent_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
    received_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
    size_bytes: Mapped[int | None] = mapped_column(BigInteger, nullable=True)

    body_text: Mapped[str | None] = mapped_column(Text, nullable=True)
    body_html: Mapped[str | None] = mapped_column(Text, nullable=True)
    has_attachments: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)

    parent_message_id: Mapped[uuid.UUID | None] = mapped_column(
        UUID(as_uuid=True), ForeignKey("messages.id"), nullable=True
    )

    is_read: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
    is_starred: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
    is_archived: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
    archived_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)

    raw_eml_path: Mapped[str | None] = mapped_column(Text, nullable=True)

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

    # Relazione con allegati (usata dal worker per inserimento)
    attachments: Mapped[list["Attachment"]] = relationship(
        "Attachment", back_populates="message", cascade="all, delete-orphan"
    )


SendJobStatus = Enum(
    "pending", "sending", "sent", "failed", "retrying",
    name="send_job_status", create_type=False,
)


class SendJob(Base):
    """
    Job di invio PEC – traccia ogni tentativo di invio SMTP.
    Corrisponde alla tabella `send_jobs` nel DB.
    """

    __tablename__ = "send_jobs"

    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), nullable=False)
    mailbox_id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), nullable=False)
    message_id: Mapped[uuid.UUID | None] = mapped_column(
        UUID(as_uuid=True),
        ForeignKey("messages.id"),
        nullable=True,
    )
    status: Mapped[str] = mapped_column(SendJobStatus, nullable=False, default="pending")
    attempt_count: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
    max_attempts: Mapped[int] = mapped_column(Integer, nullable=False, default=5)
    next_retry_at: Mapped[datetime | None] = mapped_column(
        DateTime(timezone=True), nullable=True
    )
    last_error: Mapped[str | None] = mapped_column(Text, nullable=True)
    queued_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True), server_default=func.now()
    )
    sent_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
    created_by: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True), nullable=True)


class Attachment(Base):
    """
    Allegato di un messaggio PEC.
    Corrisponde alla tabella `attachments` nel DB.
    """

    __tablename__ = "attachments"

    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), nullable=False)
    message_id: Mapped[uuid.UUID] = mapped_column(
        UUID(as_uuid=True),
        ForeignKey("messages.id", ondelete="CASCADE"),
        nullable=False,
    )
    filename: Mapped[str] = mapped_column(String(512), nullable=False)
    content_type: Mapped[str | None] = mapped_column(String(255), nullable=True)
    size_bytes: Mapped[int | None] = mapped_column(BigInteger, nullable=True)
    storage_path: Mapped[str] = mapped_column(Text, nullable=False)
    checksum_sha256: Mapped[str | None] = mapped_column(String(64), nullable=True)
    created_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True), server_default=func.now()
    )

    # Relazione inversa verso Message
    message: Mapped["Message"] = relationship("Message", back_populates="attachments")
