"""Report & moderation model.

A :class:`Report` is a Trust & Safety record raised by a student against a piece
of marketplace content. The table is deliberately **entity-generic**: every
report stores an ``entity_type`` plus an ``entity_public_id``, with optional
typed foreign keys (``listing_id`` / ``reported_user_id``) populated only for the
entity kinds actioned today. New reportable entity types (message, advertisement)
can be supported by populating ``entity_type`` / ``entity_public_id`` alone — no
schema redesign required.
"""

from __future__ import annotations

from app.extensions import db
from app.models.base import BaseModel, BigIntegerType, utcnow
from app.models.enums import ReportEntityType, ReportReason, ReportStatus
from app.models.mixins import PublicIdMixin


def _enum_values(enum_cls):
    return [member.value for member in enum_cls]


class Report(BaseModel, PublicIdMixin):
    """A moderation report raised by a student against marketplace content."""

    __tablename__ = "reports"
    __table_args__ = (
        db.Index("ix_reports_status", "status"),
        db.Index("ix_reports_entity_type", "entity_type"),
        db.Index("ix_reports_reporter_id", "reporter_id"),
        db.Index("ix_reports_moderator_id", "moderator_id"),
        db.Index("ix_reports_created_at", "created_at"),
    )

    reporter_id = db.Column(BigIntegerType, db.ForeignKey("users.id"), nullable=False)
    entity_type = db.Column(
        db.Enum(ReportEntityType, values_callable=_enum_values, name="report_entity_type"),
        nullable=False,
    )
    entity_public_id = db.Column(db.CHAR(36), nullable=False)
    # Typed FKs, populated only for the entity kinds actioned today.
    listing_id = db.Column(BigIntegerType, db.ForeignKey("listings.id"), nullable=True)
    reported_user_id = db.Column(BigIntegerType, db.ForeignKey("users.id"), nullable=True)
    reason = db.Column(
        db.Enum(ReportReason, values_callable=_enum_values, name="report_reason"),
        nullable=False,
    )
    description = db.Column(db.Text, nullable=True)
    status = db.Column(
        db.Enum(ReportStatus, values_callable=_enum_values, name="report_status"),
        nullable=False,
        default=ReportStatus.PENDING,
    )
    moderator_id = db.Column(BigIntegerType, db.ForeignKey("users.id"), nullable=True)
    moderator_notes = db.Column(db.Text, nullable=True)
    resolved_at = db.Column(db.DateTime(timezone=True), nullable=True)
    created_at = db.Column(db.DateTime(timezone=True), nullable=False, default=utcnow)

    reporter = db.relationship("User", foreign_keys=[reporter_id])
    moderator = db.relationship("User", foreign_keys=[moderator_id])
    reported_user = db.relationship("User", foreign_keys=[reported_user_id])
    listing = db.relationship("Listing", foreign_keys=[listing_id])

    # Open reports (still needing moderator attention) are those not yet closed.
    OPEN_STATUSES = (ReportStatus.PENDING, ReportStatus.UNDER_REVIEW)

    @property
    def is_open(self) -> bool:
        return self.status in self.OPEN_STATUSES

    def __repr__(self) -> str:
        return f"<Report id={self.id} entity={self.entity_type} status={self.status}>"
