"""Notification module model.

Implements the single table of the approved Notifications database design
(``docs/02_Architecture/Database/06_Notifications.md``):

* :class:`Notification` (``notifications``)

One generic table backs every notification type so all modules share the same
storage. A notification is immutable after creation except for ``read_at`` (its
read state). There is no soft delete and no ``updated_at`` column, per the
approved schema; read/unread is derived from whether ``read_at`` is set.
"""

from __future__ import annotations

from app.extensions import db
from app.models.base import BaseModel, BigIntegerType
from app.models.enums import NotificationType, RelatedEntityType
from app.models.mixins import CreatedAtMixin, PublicIdMixin


def _enum_values(enum_cls):
    """Persist the ENUM member *values* (e.g. ``"system"``) rather than names."""
    return [member.value for member in enum_cls]


class Notification(BaseModel, PublicIdMixin, CreatedAtMixin):
    """A notification delivered to a single user about a platform event."""

    __tablename__ = "notifications"
    __table_args__ = (
        # created_at comes from CreatedAtMixin; the schema indexes it.
        db.Index("ix_notifications_created_at", "created_at"),
    )

    user_id = db.Column(
        BigIntegerType, db.ForeignKey("users.id"), nullable=False, index=True
    )
    notification_type = db.Column(
        db.Enum(NotificationType, values_callable=_enum_values, name="notification_type"),
        nullable=False,
        default=NotificationType.SYSTEM,
        index=True,
    )
    title = db.Column(db.String(150), nullable=False)
    message = db.Column(db.String(500), nullable=False)
    related_entity_type = db.Column(
        db.Enum(RelatedEntityType, values_callable=_enum_values, name="related_entity_type"),
        nullable=True,
        index=True,
    )
    related_entity_id = db.Column(BigIntegerType, nullable=True, index=True)
    read_at = db.Column(db.DateTime, nullable=True, index=True)
    expires_at = db.Column(db.DateTime, nullable=True, index=True)

    # One user has many notifications, surfaced newest-first. Cascade keeps a
    # deleted user's notifications from being orphaned (matches Favorite).
    user = db.relationship(
        "User",
        backref=db.backref(
            "notifications",
            order_by="Notification.created_at.desc()",
            cascade="all, delete-orphan",
        ),
    )

    @property
    def is_read(self) -> bool:
        """True once the notification has been read (``read_at`` is set)."""
        return self.read_at is not None

    def __repr__(self) -> str:
        return f"<Notification id={self.id} user_id={self.user_id} type={self.notification_type}>"
