"""Premium subscription models (Administration module).

Phase 1 implements a *manual* premium activation workflow — Student Bazaar does
not process payments, so a student submits a :class:`PremiumRequest` describing
an out-of-band payment (UPI / bank transfer / cash) and a Super Admin reviews it.
Approving a request creates an active :class:`Subscription`.

These models define schema only; all activation, approval and entitlement logic
lives in :mod:`app.premium.services`.
"""

from __future__ import annotations

from app.extensions import db
from app.models.base import BaseModel, BigIntegerType, utcnow
from app.models.enums import PremiumRequestStatus, SubscriptionStatus
from app.models.mixins import PublicIdMixin, TimestampMixin


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


class Subscription(BaseModel, PublicIdMixin, TimestampMixin):
    """A granted premium subscription for a user.

    Created only when a Super Admin approves a :class:`PremiumRequest`. A user
    may have at most one ``ACTIVE`` subscription at a time; historical rows are
    kept (status ``EXPIRED``/``CANCELLED``) so the subscription history is never
    lost.
    """

    __tablename__ = "subscriptions"
    __table_args__ = (
        db.Index("ix_subscriptions_user_id", "user_id"),
        db.Index("ix_subscriptions_status", "status"),
        db.Index("ix_subscriptions_end_date", "end_date"),
    )

    user_id = db.Column(
        BigIntegerType, db.ForeignKey("users.id"), nullable=False
    )
    plan_name = db.Column(db.String(50), nullable=False)
    status = db.Column(
        db.Enum(SubscriptionStatus, values_callable=_enum_values, name="subscription_status"),
        nullable=False,
        default=SubscriptionStatus.ACTIVE,
    )
    start_date = db.Column(db.DateTime, nullable=False)
    end_date = db.Column(db.DateTime, nullable=False)
    # The Super Admin who approved the activation (audit trail).
    activated_by = db.Column(
        BigIntegerType, db.ForeignKey("users.id"), nullable=True
    )

    user = db.relationship("User", foreign_keys=[user_id])
    activator = db.relationship("User", foreign_keys=[activated_by])

    def __repr__(self) -> str:
        return (
            f"<Subscription id={self.id} user_id={self.user_id} "
            f"plan={self.plan_name!r} status={self.status.value!r}>"
        )


class PremiumRequest(BaseModel, PublicIdMixin):
    """A student's request to be activated as a premium member.

    Describes an out-of-band payment for a Super Admin to verify. On approval a
    :class:`Subscription` is created; on rejection nothing is granted. The row is
    retained either way as an auditable record of the decision.
    """

    __tablename__ = "premium_requests"
    __table_args__ = (
        db.Index("ix_premium_requests_user_id", "user_id"),
        db.Index("ix_premium_requests_status", "status"),
        db.Index("ix_premium_requests_requested_at", "requested_at"),
    )

    user_id = db.Column(
        BigIntegerType, db.ForeignKey("users.id"), nullable=False
    )
    plan_name = db.Column(db.String(50), nullable=False)
    payment_method = db.Column(db.String(30), nullable=False)
    transaction_reference = db.Column(db.String(120), nullable=True)
    # Optional payment-receipt screenshot filename (served to owner/admin only).
    receipt_path = db.Column(db.String(255), nullable=True)
    remarks = db.Column(db.Text, nullable=True)
    # Admin's note/reason recorded on review (e.g. why a request was rejected).
    review_note = db.Column(db.Text, nullable=True)
    status = db.Column(
        db.Enum(PremiumRequestStatus, values_callable=_enum_values, name="premium_request_status"),
        nullable=False,
        default=PremiumRequestStatus.PENDING,
    )
    requested_at = db.Column(db.DateTime, nullable=False, default=utcnow)
    reviewed_at = db.Column(db.DateTime, nullable=True)
    # The Super Admin who approved/rejected the request (audit trail).
    reviewed_by = db.Column(
        BigIntegerType, db.ForeignKey("users.id"), nullable=True
    )

    user = db.relationship("User", foreign_keys=[user_id])
    reviewer = db.relationship("User", foreign_keys=[reviewed_by])

    def __repr__(self) -> str:
        return (
            f"<PremiumRequest id={self.id} user_id={self.user_id} "
            f"status={self.status.value!r}>"
        )
