"""
Modelli RoutingRule, RoutingRuleCondition, RoutingRuleAction.

Le regole di smistamento automatico vengono valutate a ogni messaggio in arrivo:
  1. Si caricano tutte le regole attive del tenant, ordinate per priority ASC
  2. Per ogni regola si valutano le condizioni (AND tra le condizioni della stessa regola)
  3. Se tutte le condizioni sono soddisfatte, si eseguono le azioni
  4. Se stop_processing=True, si ferma l'elaborazione (non vengono valutate regole successive)
"""

import uuid
from datetime import datetime

from sqlalchemy import Boolean, DateTime, ForeignKey, Index, Integer, String, Text, func
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.orm import Mapped, mapped_column, relationship

from app.database import Base


class RoutingRule(Base):
    __tablename__ = "routing_rules"

    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
    )
    name: Mapped[str] = mapped_column(String(255), nullable=False)
    description: Mapped[str | None] = mapped_column(Text, nullable=True)
    is_active: Mapped[bool] = mapped_column(Boolean, nullable=False, default=True)
    priority: Mapped[int] = mapped_column(Integer, nullable=False, default=100)
    # Se True, le regole successive non vengono valutate una volta che questa fa match
    stop_processing: Mapped[bool] = mapped_column(Boolean, nullable=False, default=True)
    created_by: Mapped[uuid.UUID | None] = mapped_column(
        UUID(as_uuid=True), ForeignKey("users.id", ondelete="SET NULL"), nullable=True
    )
    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()
    )

    # Relazioni
    conditions: Mapped[list["RoutingRuleCondition"]] = relationship(
        "RoutingRuleCondition", back_populates="rule", cascade="all, delete-orphan"
    )
    actions: Mapped[list["RoutingRuleAction"]] = relationship(
        "RoutingRuleAction", back_populates="rule", cascade="all, delete-orphan"
    )

    __table_args__ = (
        Index("idx_routing_rules_tenant", "tenant_id"),
        Index("idx_routing_rules_active", "tenant_id", "priority"),
    )

    def __repr__(self) -> str:
        return f"<RoutingRule {self.name!r} priority={self.priority}>"


class RoutingRuleCondition(Base):
    """
    Singola condizione di una regola.

    field    : from_address | to_address | subject | mailbox_id | pec_type
    operator : contains | equals | starts_with | ends_with | regex | not_contains
    value    : valore da confrontare (stringa)
    """

    __tablename__ = "routing_rule_conditions"

    id: Mapped[uuid.UUID] = mapped_column(
        UUID(as_uuid=True), primary_key=True, default=uuid.uuid4
    )
    rule_id: Mapped[uuid.UUID] = mapped_column(
        UUID(as_uuid=True), ForeignKey("routing_rules.id", ondelete="CASCADE"), nullable=False
    )
    field: Mapped[str] = mapped_column(String(50), nullable=False)
    operator: Mapped[str] = mapped_column(String(30), nullable=False, default="contains")
    value: Mapped[str] = mapped_column(Text, nullable=False)

    rule: Mapped["RoutingRule"] = relationship("RoutingRule", back_populates="conditions")

    __table_args__ = (
        Index("idx_routing_conditions_rule", "rule_id"),
    )


class RoutingRuleAction(Base):
    """
    Singola azione di una regola.

    action_type  : apply_label | assign_vbox | mark_read | mark_starred | notify_webhook
    action_value : UUID della label/vbox, o URL del webhook
    """

    __tablename__ = "routing_rule_actions"

    id: Mapped[uuid.UUID] = mapped_column(
        UUID(as_uuid=True), primary_key=True, default=uuid.uuid4
    )
    rule_id: Mapped[uuid.UUID] = mapped_column(
        UUID(as_uuid=True), ForeignKey("routing_rules.id", ondelete="CASCADE"), nullable=False
    )
    action_type: Mapped[str] = mapped_column(String(50), nullable=False)
    action_value: Mapped[str | None] = mapped_column(Text, nullable=True)

    rule: Mapped["RoutingRule"] = relationship("RoutingRule", back_populates="actions")

    __table_args__ = (
        Index("idx_routing_actions_rule", "rule_id"),
    )
