"""
Schemi Pydantic per Message, Attachment e operazioni correlate.
"""

import uuid
from datetime import datetime
from typing import Optional

from pydantic import BaseModel, model_validator

from app.schemas.label import LabelResponse


# ─── Search match info ────────────────────────────────────────────────────────

class AttachmentMatchInfo(BaseModel):
    """Allegato in cui e' stato trovato il termine cercato."""
    id: uuid.UUID
    filename: str

    model_config = {"from_attributes": True}


class SearchMatchInfo(BaseModel):
    """Indica dove e' stato trovato il termine di ricerca in un messaggio."""
    in_subject: bool = False
    in_body: bool = False
    in_attachments: list[AttachmentMatchInfo] = []

    model_config = {"from_attributes": True}


# ─── Attachment ───────────────────────────────────────────────────────────────

class AttachmentResponse(BaseModel):
    id: uuid.UUID
    message_id: uuid.UUID
    filename: str
    content_type: Optional[str] = None
    size_bytes: Optional[int] = None
    storage_path: str
    checksum_sha256: Optional[str] = None
    created_at: datetime

    model_config = {"from_attributes": True}


class MessageResponse(BaseModel):
    id: uuid.UUID
    tenant_id: uuid.UUID
    mailbox_id: uuid.UUID
    message_id_header: Optional[str] = None
    imap_uid: Optional[int] = None
    imap_folder: str
    direction: str
    pec_type: str
    state: str
    subject: Optional[str] = None
    from_address: Optional[str] = None
    to_addresses: list[str] = []
    cc_addresses: list[str] = []
    sent_at: Optional[datetime] = None
    received_at: Optional[datetime] = None
    size_bytes: Optional[int] = None
    body_text: Optional[str] = None
    body_html: Optional[str] = None
    has_attachments: bool = False
    parent_message_id: Optional[uuid.UUID] = None
    is_read: bool = False
    is_starred: bool = False
    is_archived: bool = False
    archived_at: Optional[datetime] = None
    is_trashed: bool = False
    trashed_at: Optional[datetime] = None
    is_pending_conservation: bool = False
    pending_conservation_at: Optional[datetime] = None
    is_conserved: bool = False
    conserved_at: Optional[datetime] = None
    # Rischio e Riservatezza (Feature N3)
    risk_level: Optional[str] = None
    confidentiality: Optional[str] = None
    raw_eml_path: Optional[str] = None
    created_at: datetime
    updated_at: datetime
    labels: list[LabelResponse] = []
    # Popolato solo nelle risposte di ricerca full-text
    search_match: Optional[SearchMatchInfo] = None

    @model_validator(mode="before")
    @classmethod
    def coerce_arrays(cls, data: object) -> object:
        """Normalizza i campi array a liste vuote se None (da ORM)."""
        if hasattr(data, "__dict__"):
            # ORM object
            for field in ("to_addresses", "cc_addresses"):
                val = getattr(data, field, None)
                if val is None:
                    object.__setattr__(data, field, [])
        elif isinstance(data, dict):
            for field in ("to_addresses", "cc_addresses"):
                if data.get(field) is None:
                    data[field] = []
        return data

    model_config = {"from_attributes": True}


class MessageListResponse(BaseModel):
    items: list[MessageResponse]
    total: int
    page: int
    page_size: int


class MessageUpdateRequest(BaseModel):
    is_read: Optional[bool] = None
    is_starred: Optional[bool] = None
    is_archived: Optional[bool] = None
    is_trashed: Optional[bool] = None
    is_pending_conservation: Optional[bool] = None
    is_conserved: Optional[bool] = None
    # Rischio e Riservatezza (Feature N3) — None = non modificare; stringa vuota = reset a NULL
    risk_level: Optional[str] = None
    confidentiality: Optional[str] = None


class MessageBulkUpdateRequest(BaseModel):
    ids: list[uuid.UUID]
    is_read: Optional[bool] = None
    is_starred: Optional[bool] = None
    is_archived: Optional[bool] = None
    is_trashed: Optional[bool] = None
    is_pending_conservation: Optional[bool] = None
    is_conserved: Optional[bool] = None
    risk_level: Optional[str] = None
    confidentiality: Optional[str] = None


class MessageBulkUpdateResponse(BaseModel):
    updated: int
    items: list[MessageResponse]
