from __future__ import annotations

from datetime import datetime
from typing import Optional
from uuid import UUID

from sqlalchemy import DateTime, ForeignKey, Index, String, Text
from sqlalchemy.dialects.postgresql import UUID as PG_UUID
from sqlalchemy.orm import Mapped, mapped_column

from src.database.base import BaseModel


class Notification(BaseModel):
    """One in-app notification delivered to the admin notification bell.

    Deliberately inherits `BaseModel`, not `TenantModel`: platform-scoped
    notifications (for `site_admin` users, who have no `tenant_id` at all)
    must be storable with `tenant_id = NULL`. `recipient_scope` is therefore
    the primary discriminator and **every** query must filter on it —
    Row-Level Security is defined but inactive in this database, so scope and
    tenant isolation are enforced only by hand-written WHERE clauses.

    `user_id` is nullable and means "any admin in this scope" when NULL. It
    exists now so per-user targeting can be added later without a migration.
    """

    __tablename__ = "notifications"

    __table_args__ = (
        # Badge count + newest-first list, for both scopes.
        Index(
            "idx_notifications_scope_tenant_read_created",
            "recipient_scope",
            "tenant_id",
            "read_at",
            "created_at",
        ),
        # Dedupe / lookup by originating entity.
        Index("idx_notifications_entity", "entity_type", "entity_id"),
    )

    recipient_scope: Mapped[str] = mapped_column(String(20), nullable=False)

    # NULL for platform-scoped rows. No FK ondelete=CASCADE mismatch risk:
    # deleting an account should take its notifications with it.
    tenant_id: Mapped[Optional[UUID]] = mapped_column(
        PG_UUID(as_uuid=True),
        ForeignKey("accounts.id", ondelete="CASCADE"),
        nullable=True,
        index=True,
    )

    # NULL = broadcast to every admin in the scope.
    user_id: Mapped[Optional[UUID]] = mapped_column(
        PG_UUID(as_uuid=True),
        ForeignKey("users.id", ondelete="CASCADE"),
        nullable=True,
    )

    type: Mapped[str] = mapped_column(String(50), nullable=False)
    title: Mapped[str] = mapped_column(String(200), nullable=False)
    body: Mapped[Optional[str]] = mapped_column(Text, nullable=True)

    entity_type: Mapped[Optional[str]] = mapped_column(String(50), nullable=True)
    entity_id: Mapped[Optional[UUID]] = mapped_column(PG_UUID(as_uuid=True), nullable=True)

    # Pre-resolved relative path the bell navigates to on click.
    link: Mapped[Optional[str]] = mapped_column(String(500), nullable=True)

    read_at: Mapped[Optional[datetime]] = mapped_column(
        DateTime(timezone=True), nullable=True, default=None
    )
