"""SQLAlchemy models for the Mail plugin."""

from __future__ import annotations

import uuid
from datetime import UTC, datetime

from sqlalchemy import (
    Boolean,
    DateTime,
    ForeignKey,
    Index,
    Integer,
    JSON,
    String,
    Text,
    UniqueConstraint,
)
from sqlalchemy.dialects.postgresql import UUID as PGUUID
from sqlalchemy.orm import Mapped, mapped_column

from app.core.db import Base, TenantMixin

# --- Mail Accounts (F-MAIL-14, F-MAIL-18) ---


class MailAccount(Base, TenantMixin):
    """Mail account configuration with encrypted IMAP/SMTP credentials."""

    __tablename__ = "mail_accounts"
    __table_args__ = (
        Index("ix_mail_accounts_user", "user_id"),
        Index("ix_mail_accounts_tenant", "tenant_id"),
    )

    id: Mapped[uuid.UUID] = mapped_column(
        PGUUID(as_uuid=True), primary_key=True, default=uuid.uuid4
    )
    user_id: Mapped[uuid.UUID] = mapped_column(PGUUID(as_uuid=True), nullable=False)
    email_address: Mapped[str] = mapped_column(String(255), nullable=False)
    display_name: Mapped[str] = mapped_column(String(255), nullable=False, default="")
    imap_host: Mapped[str] = mapped_column(String(255), nullable=False)
    imap_port: Mapped[int] = mapped_column(Integer, nullable=False, default=993)
    imap_ssl: Mapped[bool] = mapped_column(Boolean, nullable=False, default=True)
    smtp_host: Mapped[str] = mapped_column(String(255), nullable=False)
    smtp_port: Mapped[int] = mapped_column(Integer, nullable=False, default=587)
    smtp_tls: Mapped[bool] = mapped_column(Boolean, nullable=False, default=True)
    username: Mapped[str] = mapped_column(String(255), nullable=False)
    encrypted_password: Mapped[str] = mapped_column(Text, nullable=False)
    password_salt: Mapped[str] = mapped_column(String(64), nullable=False, default="")  # base64-encoded random salt
    is_shared: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
    is_active: Mapped[bool] = mapped_column(Boolean, nullable=False, default=True)
    sent_folder_imap_name: Mapped[str | None] = mapped_column(String(255), nullable=True)
    drafts_folder_imap_name: Mapped[str | None] = mapped_column(String(255), nullable=True)
    spam_folder_imap_name: Mapped[str | None] = mapped_column(String(255), nullable=True)
    trash_folder_imap_name: Mapped[str | None] = mapped_column(String(255), nullable=True)
    deleted_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)


# --- Mail Folders (F-MAIL-01, F-MAIL-19) ---


class MailFolder(Base, TenantMixin):
    """IMAP folder mapped to a mail account."""

    __tablename__ = "mail_folders"
    __table_args__ = (
        Index("ix_mail_folders_account", "account_id"),
        Index("ix_mail_folders_tenant", "tenant_id"),
    )

    id: Mapped[uuid.UUID] = mapped_column(
        PGUUID(as_uuid=True), primary_key=True, default=uuid.uuid4
    )
    account_id: Mapped[uuid.UUID] = mapped_column(
        PGUUID(as_uuid=True),
        ForeignKey("mail_accounts.id", ondelete="CASCADE"),
        nullable=False,
    )
    name: Mapped[str] = mapped_column(String(255), nullable=False)
    imap_name: Mapped[str] = mapped_column(String(255), nullable=False)
    parent_id: Mapped[uuid.UUID | None] = mapped_column(
        PGUUID(as_uuid=True),
        ForeignKey("mail_folders.id", ondelete="CASCADE"),
        nullable=True,
    )
    is_standard: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
    unread_count: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
    total_count: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
    deleted_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)


# --- Mails (F-MAIL-01, F-MAIL-03, F-MAIL-05) ---


class Mail(Base, TenantMixin):
    """Individual email message stored locally after IMAP sync."""

    __tablename__ = "mails"
    __table_args__ = (
        Index("ix_mails_folder", "folder_id"),
        Index("ix_mails_account", "account_id"),
        Index("ix_mails_tenant", "tenant_id"),
        Index("ix_mails_thread", "thread_id"),
    )

    id: Mapped[uuid.UUID] = mapped_column(
        PGUUID(as_uuid=True), primary_key=True, default=uuid.uuid4
    )
    account_id: Mapped[uuid.UUID] = mapped_column(
        PGUUID(as_uuid=True),
        ForeignKey("mail_accounts.id", ondelete="CASCADE"),
        nullable=False,
    )
    folder_id: Mapped[uuid.UUID] = mapped_column(
        PGUUID(as_uuid=True),
        ForeignKey("mail_folders.id", ondelete="CASCADE"),
        nullable=False,
    )
    imap_uid: Mapped[str | None] = mapped_column(String(20), nullable=True)
    message_id: Mapped[str] = mapped_column(String(512), nullable=False)
    thread_id: Mapped[str] = mapped_column(String(512), nullable=False, default="")
    in_reply_to: Mapped[str | None] = mapped_column(String(512), nullable=True)
    references_header: Mapped[str | None] = mapped_column(Text, nullable=True)
    subject: Mapped[str] = mapped_column(String(512), nullable=False, default="")
    from_address: Mapped[str] = mapped_column(String(255), nullable=False)
    to_addresses: Mapped[str] = mapped_column(Text, nullable=False, default="")
    cc_addresses: Mapped[str] = mapped_column(Text, nullable=False, default="")
    bcc_addresses: Mapped[str] = mapped_column(Text, nullable=False, default="")
    body_text: Mapped[str] = mapped_column(Text, nullable=False, default="")
    body_html: Mapped[str] = mapped_column(Text, nullable=False, default="")
    body_html_sanitized: Mapped[str] = mapped_column(Text, nullable=False, default="")
    is_seen: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
    is_flagged: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
    flag_type: Mapped[str | None] = mapped_column(String(32), nullable=True, default=None)
    is_draft: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
    is_answered: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
    is_forwarded: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
    has_attachments: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
    size_bytes: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
    received_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
    sent_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
    contact_id: Mapped[uuid.UUID | None] = mapped_column(PGUUID(as_uuid=True), nullable=True)
    deleted_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)


# --- Mail Attachments (F-MAIL-04) ---


class MailAttachment(Base, TenantMixin):
    """Attachment on a mail, optionally linked to a DMS file."""

    __tablename__ = "mail_attachments"
    __table_args__ = (
        Index("ix_mail_attachments_mail", "mail_id"),
        Index("ix_mail_attachments_tenant", "tenant_id"),
    )

    id: Mapped[uuid.UUID] = mapped_column(
        PGUUID(as_uuid=True), primary_key=True, default=uuid.uuid4
    )
    mail_id: Mapped[uuid.UUID] = mapped_column(
        PGUUID(as_uuid=True),
        ForeignKey("mails.id", ondelete="CASCADE"),
        nullable=False,
    )
    filename: Mapped[str] = mapped_column(String(255), nullable=False)
    mime_type: Mapped[str] = mapped_column(
        String(255), nullable=False, default="application/octet-stream"
    )
    size_bytes: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
    storage_path: Mapped[str] = mapped_column(String(1024), nullable=False)
    dms_file_id: Mapped[uuid.UUID | None] = mapped_column(PGUUID(as_uuid=True), nullable=True)
    content_id: Mapped[str | None] = mapped_column(String(255), nullable=True)


# --- Mail Labels (F-MAIL-09) ---


class MailLabel(Base, TenantMixin):
    """Custom label/tag for mails (colored)."""

    __tablename__ = "mail_labels"
    __table_args__ = (Index("ix_mail_labels_tenant", "tenant_id"),)

    id: Mapped[uuid.UUID] = mapped_column(
        PGUUID(as_uuid=True), primary_key=True, default=uuid.uuid4
    )
    name: Mapped[str] = mapped_column(String(100), nullable=False)
    color: Mapped[str] = mapped_column(String(20), nullable=False, default="#808080")
    user_id: Mapped[uuid.UUID] = mapped_column(PGUUID(as_uuid=True), nullable=False)


class MailLabelAssignment(Base, TenantMixin):
    """Many-to-many: mail <-> label."""

    __tablename__ = "mail_label_assignments"
    __table_args__ = (
        UniqueConstraint("mail_id", "label_id", name="uq_mail_label_assignment"),
        Index("ix_mail_label_assign_mail", "mail_id"),
        Index("ix_mail_label_assign_label", "label_id"),
    )

    id: Mapped[uuid.UUID] = mapped_column(
        PGUUID(as_uuid=True), primary_key=True, default=uuid.uuid4
    )
    mail_id: Mapped[uuid.UUID] = mapped_column(
        PGUUID(as_uuid=True),
        ForeignKey("mails.id", ondelete="CASCADE"),
        nullable=False,
    )
    label_id: Mapped[uuid.UUID] = mapped_column(
        PGUUID(as_uuid=True),
        ForeignKey("mail_labels.id", ondelete="CASCADE"),
        nullable=False,
    )


# --- Mail Rules (F-MAIL-07) ---


class MailRule(Base, TenantMixin):
    """Filter rule: conditions to actions for incoming mails."""

    __tablename__ = "mail_rules"
    __table_args__ = (
        Index("ix_mail_rules_account", "account_id"),
        Index("ix_mail_rules_tenant", "tenant_id"),
    )

    id: Mapped[uuid.UUID] = mapped_column(
        PGUUID(as_uuid=True), primary_key=True, default=uuid.uuid4
    )
    account_id: Mapped[uuid.UUID | None] = mapped_column(
        PGUUID(as_uuid=True),
        ForeignKey("mail_accounts.id", ondelete="CASCADE"),
        nullable=True,
    )
    name: Mapped[str] = mapped_column(String(255), nullable=False)
    priority: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
    is_active: Mapped[bool] = mapped_column(Boolean, nullable=False, default=True)
    conditions: Mapped[str] = mapped_column(Text, nullable=False, default="{}")
    actions: Mapped[str] = mapped_column(Text, nullable=False, default="{}")


# --- Mail Templates (F-MAIL-06) ---


class MailTemplate(Base, TenantMixin):
    """Email template with placeholder substitution."""

    __tablename__ = "mail_templates"
    __table_args__ = (Index("ix_mail_templates_tenant", "tenant_id"),)

    id: Mapped[uuid.UUID] = mapped_column(
        PGUUID(as_uuid=True), primary_key=True, default=uuid.uuid4
    )
    name: Mapped[str] = mapped_column(String(255), nullable=False)
    subject: Mapped[str] = mapped_column(String(512), nullable=False, default="")
    body_html: Mapped[str] = mapped_column(Text, nullable=False, default="")
    user_id: Mapped[uuid.UUID] = mapped_column(PGUUID(as_uuid=True), nullable=False)


# --- Mail Signatures (F-MAIL-13) ---


class MailSignature(Base, TenantMixin):
    """Email signature (HTML) per user, optionally per account."""

    __tablename__ = "mail_signatures"
    __table_args__ = (Index("ix_mail_signatures_tenant", "tenant_id"),)

    id: Mapped[uuid.UUID] = mapped_column(
        PGUUID(as_uuid=True), primary_key=True, default=uuid.uuid4
    )
    user_id: Mapped[uuid.UUID] = mapped_column(PGUUID(as_uuid=True), nullable=False)
    account_id: Mapped[uuid.UUID | None] = mapped_column(
        PGUUID(as_uuid=True),
        ForeignKey("mail_accounts.id", ondelete="CASCADE"),
        nullable=True,
    )
    name: Mapped[str] = mapped_column(String(255), nullable=False)
    body_html: Mapped[str] = mapped_column(Text, nullable=False, default="")
    is_default: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)


# --- Vacation Auto-Reply (F-MAIL-08) ---


class VacationSentLog(Base, TenantMixin):
    """Dedup log for vacation auto-replies (one per sender per 24 hours)."""

    __tablename__ = "vacation_sent_log"
    __table_args__ = (
        Index("ix_vacation_sent_log_account", "account_id"),
        Index("ix_vacation_sent_log_tenant", "tenant_id"),
    )

    id: Mapped[uuid.UUID] = mapped_column(
        PGUUID(as_uuid=True), primary_key=True, default=uuid.uuid4
    )
    account_id: Mapped[uuid.UUID] = mapped_column(
        PGUUID(as_uuid=True),
        ForeignKey("mail_accounts.id", ondelete="CASCADE"),
        nullable=False,
    )
    sender_address: Mapped[str] = mapped_column(String(255), nullable=False)
    sent_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False)


# --- Seen-By Tracking (F-MAIL-15) ---


class MailSeenBy(Base, TenantMixin):
    """Tracks which users have seen a mail in a shared mailbox."""

    __tablename__ = "mail_seen_by"
    __table_args__ = (
        UniqueConstraint("mail_id", "user_id", name="uq_mail_seen_by"),
        Index("ix_mail_seen_by_mail", "mail_id"),
    )

    id: Mapped[uuid.UUID] = mapped_column(
        PGUUID(as_uuid=True), primary_key=True, default=uuid.uuid4
    )
    mail_id: Mapped[uuid.UUID] = mapped_column(
        PGUUID(as_uuid=True),
        ForeignKey("mails.id", ondelete="CASCADE"),
        nullable=False,
    )
    user_id: Mapped[uuid.UUID] = mapped_column(PGUUID(as_uuid=True), nullable=False)
    seen_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False)


# --- Delegates (F-MAIL-16) ---


class MailAccountDelegate(Base, TenantMixin):
    """Delegate access to a mail account.

    access_level values:
    - "read" → Mails lesen, suchen, Threads sehen
    - "write" → read + Flags setzen, verschieben, Entwürfe speichern
    - "delete" → write + Mails löschen
    - "full" → delete + Ordner verwalten + ACLs vergeben
    """

    __tablename__ = "mail_account_delegates"
    __table_args__ = (
        UniqueConstraint("account_id", "delegate_user_id", name="uq_mail_delegate"),
        Index("ix_mail_delegates_account", "account_id"),
    )

    id: Mapped[uuid.UUID] = mapped_column(
        PGUUID(as_uuid=True), primary_key=True, default=uuid.uuid4
    )
    account_id: Mapped[uuid.UUID] = mapped_column(
        PGUUID(as_uuid=True),
        ForeignKey("mail_accounts.id", ondelete="CASCADE"),
        nullable=False,
    )
    delegate_user_id: Mapped[uuid.UUID] = mapped_column(PGUUID(as_uuid=True), nullable=False)
    access_level: Mapped[str] = mapped_column(String(20), nullable=False, default="read")


# --- Send Permissions (F-MAIL-17) ---


class MailAccountSendPermission(Base, TenantMixin):
    """Permission for a user to send as a shared/group mailbox."""

    __tablename__ = "mail_account_send_permissions"
    __table_args__ = (
        UniqueConstraint("account_id", "user_id", name="uq_mail_send_perm"),
        Index("ix_mail_send_perms_account", "account_id"),
    )

    id: Mapped[uuid.UUID] = mapped_column(
        PGUUID(as_uuid=True), primary_key=True, default=uuid.uuid4
    )
    account_id: Mapped[uuid.UUID] = mapped_column(
        PGUUID(as_uuid=True),
        ForeignKey("mail_accounts.id", ondelete="CASCADE"),
        nullable=False,
    )
    user_id: Mapped[uuid.UUID] = mapped_column(PGUUID(as_uuid=True), nullable=False)


# --- PGP Keys (F-MAIL-12) ---


class PgpKey(Base, TenantMixin):
    """PGP private key for a user (encrypted at rest)."""

    __tablename__ = "pgp_keys"
    __table_args__ = (Index("ix_pgp_keys_user", "user_id"),)

    id: Mapped[uuid.UUID] = mapped_column(
        PGUUID(as_uuid=True), primary_key=True, default=uuid.uuid4
    )
    user_id: Mapped[uuid.UUID] = mapped_column(PGUUID(as_uuid=True), nullable=False)
    key_id: Mapped[str] = mapped_column(String(255), nullable=False)
    encrypted_private_key: Mapped[str] = mapped_column(Text, nullable=False)
    public_key_armored: Mapped[str] = mapped_column(Text, nullable=False)


class ContactPgpKey(Base, TenantMixin):
    """Public PGP key for a contact."""

    __tablename__ = "contact_pgp_keys"
    __table_args__ = (Index("ix_contact_pgp_keys_contact", "contact_id"),)

    id: Mapped[uuid.UUID] = mapped_column(
        PGUUID(as_uuid=True), primary_key=True, default=uuid.uuid4
    )
    contact_id: Mapped[uuid.UUID] = mapped_column(PGUUID(as_uuid=True), nullable=False)
    public_key_armored: Mapped[str] = mapped_column(Text, nullable=False)
    key_id: Mapped[str] = mapped_column(String(255), nullable=False, default="")


class MailSyncQueue(Base, TenantMixin):
    """Queue for pending IMAP operations that need retry."""

    __tablename__ = "mail_sync_queue"
    __table_args__ = (
        Index("ix_mail_sync_queue_status", "status"),
        Index("ix_mail_sync_queue_mail", "mail_id"),
    )

    id: Mapped[uuid.UUID] = mapped_column(
        PGUUID(as_uuid=True), primary_key=True, default=uuid.uuid4
    )
    mail_id: Mapped[uuid.UUID] = mapped_column(PGUUID(as_uuid=True), nullable=False)
    operation: Mapped[str] = mapped_column(String(50), nullable=False)
    payload: Mapped[dict] = mapped_column(JSON, nullable=False, default=dict)
    status: Mapped[str] = mapped_column(String(20), nullable=False, default="pending")
    attempts: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
    max_attempts: Mapped[int] = mapped_column(Integer, nullable=False, default=3)
    last_error: Mapped[str | None] = mapped_column(Text, nullable=True)
    created_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True), nullable=False, default=lambda: datetime.now(UTC)
    )
    updated_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True), nullable=False, default=lambda: datetime.now(UTC)
    )
