"""مدل‌های Outbox و Inbox برای الگوی رویداد قابل اعتماد.

OutboxEvent: رویدادهای خروجی که باید منتشر شوند.
InboxEvent: رویدادهای ورودی برای idempotency و جلوگیری از پردازش تکراری.
"""
from __future__ import annotations

import uuid
from datetime import datetime

from sqlalchemy import DateTime
from sqlalchemy import Enum as SAEnum
from sqlalchemy import Index, Integer, String, func
from sqlalchemy.orm import Mapped, mapped_column
from sqlalchemy.types import JSON

from app.core.database import Base
from app.models.base import UUIDPrimaryKeyMixin
from app.models.types import GUID
from shared.events import EventStatus


class OutboxEvent(UUIDPrimaryKeyMixin, Base):
    __tablename__ = "outbox_events"

    event_type: Mapped[str] = mapped_column(String(150), nullable=False)
    aggregate_type: Mapped[str] = mapped_column(String(100), nullable=False)
    aggregate_id: Mapped[str | None] = mapped_column(String(100), nullable=True)
    tenant_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    payload: Mapped[dict] = mapped_column(JSON, nullable=False, default=dict)
    status: Mapped[EventStatus] = mapped_column(
        SAEnum(EventStatus, name="event_status"),
        default=EventStatus.PENDING,
        nullable=False,
    )
    retry_count: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
    created_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True), server_default=func.now(), nullable=False
    )
    processed_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)

    __table_args__ = (
        Index("ix_outbox_events_status", "status"),
        Index("ix_outbox_events_tenant_id", "tenant_id"),
    )


class InboxEvent(UUIDPrimaryKeyMixin, Base):
    __tablename__ = "inbox_events"

    # شناسه یکتای رویداد منبع برای جلوگیری از پردازش تکراری (idempotency).
    event_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False, unique=True)
    source_service: Mapped[str] = mapped_column(String(100), nullable=False)
    event_type: Mapped[str] = mapped_column(String(150), nullable=False)
    tenant_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    payload: Mapped[dict] = mapped_column(JSON, nullable=False, default=dict)
    processed_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)

    __table_args__ = (
        Index("ix_inbox_events_event_id", "event_id", unique=True),
        Index("ix_inbox_events_tenant_id", "tenant_id"),
    )
