from __future__ import annotations

import uuid
from datetime import datetime
from enum import Enum

from sqlalchemy import CheckConstraint, DateTime, ForeignKey, Integer, String
from sqlalchemy.dialects.postgresql import JSONB, UUID
from sqlalchemy.orm import Mapped, mapped_column

from core.db.base import Base, TimestampMixin


class InviteCodeStatus(str, Enum):
    ACTIVE = "active"
    DISABLED = "disabled"
    EXPIRED = "expired"


class InviteCode(TimestampMixin, Base):
    """Invite code model.

    Tracks invite codes generated by users for referral system.
    """

    __tablename__: str = "invite_codes"
    __table_args__ = (
        CheckConstraint(
            "status IN ('active', 'disabled', 'expired')",
            name="invite_codes_status_check",
        ),
        CheckConstraint("used_count >= 0", name="invite_codes_used_count_check"),
        CheckConstraint(
            "max_uses IS NULL OR max_uses >= 1",
            name="invite_codes_max_uses_check",
        ),
        {"extend_existing": True},
    )

    id: Mapped[uuid.UUID] = mapped_column(
        UUID(as_uuid=True),
        primary_key=True,
        default=uuid.uuid4,
    )
    code: Mapped[str] = mapped_column(
        String(8),
        nullable=False,
        unique=True,
        index=True,
    )
    owner_id: Mapped[uuid.UUID | None] = mapped_column(
        UUID(as_uuid=True),
        ForeignKey("profiles.id", ondelete="SET NULL"),
        nullable=True,
        index=True,
    )
    status: Mapped[str] = mapped_column(
        String(20),
        nullable=False,
        default=InviteCodeStatus.ACTIVE.value,
    )
    used_count: Mapped[int] = mapped_column(
        Integer,
        nullable=False,
        default=0,
    )
    max_uses: Mapped[int | None] = mapped_column(
        Integer,
        nullable=True,
    )
    expires_at: Mapped[datetime | None] = mapped_column(
        DateTime(timezone=True),
        nullable=True,
    )
    reward_config: Mapped[dict] = mapped_column(
        JSONB,
        nullable=False,
        server_default="{}",
    )
