import enum
from datetime import datetime

from sqlalchemy import BigInteger, Boolean, DateTime, Enum as SAEnum, Integer, String, Text
from sqlalchemy.orm import Mapped, mapped_column

from app.models.base import BaseModel


class UserRole(str, enum.Enum):
    USER = "user"
    ADMIN = "admin"
    SUPER_ADMIN = "super_admin"


class UserStatus(str, enum.Enum):
    ACTIVE = "active"
    INACTIVE = "inactive"
    BANNED = "banned"


class IdCardVerifiedStatus(str, enum.Enum):
    UNVERIFIED = "unverified"
    PENDING = "pending"
    VERIFIED = "verified"
    REJECTED = "rejected"


class User(BaseModel):
    __tablename__ = "users"

    email: Mapped[str | None] = mapped_column(String(255), unique=True, index=True, nullable=True)
    username: Mapped[str] = mapped_column(String(50), unique=True, index=True, nullable=False)
    hashed_password: Mapped[str | None] = mapped_column(String(255), nullable=True)
    phone: Mapped[str | None] = mapped_column(String(20), unique=True, index=True, nullable=True)
    id_card_no: Mapped[str | None] = mapped_column(String(255), unique=True, index=True, nullable=True)
    id_card_no_hash: Mapped[str | None] = mapped_column(String(64), unique=True, index=True, nullable=True)
    real_name: Mapped[str | None] = mapped_column(String(255), nullable=True)
    id_card_verified: Mapped[str] = mapped_column(
        String(20),
        default=IdCardVerifiedStatus.UNVERIFIED.value,
        nullable=False,
    )
    id_card_verified_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
    id_card_front_image: Mapped[str | None] = mapped_column(String(500), nullable=True)
    id_card_back_image: Mapped[str | None] = mapped_column(String(500), nullable=True)
    id_card_face_image: Mapped[str | None] = mapped_column(String(500), nullable=True)
    id_card_verify_remark: Mapped[str | None] = mapped_column(Text, nullable=True)
    avatar: Mapped[str | None] = mapped_column(String(500), nullable=True)
    nickname: Mapped[str | None] = mapped_column(String(100), nullable=True)
    role: Mapped[UserRole] = mapped_column(
        SAEnum(UserRole, values_callable=lambda e: [m.value for m in e]),
        default=UserRole.USER,
        nullable=False,
    )
    status: Mapped[UserStatus] = mapped_column(
        SAEnum(UserStatus, values_callable=lambda e: [m.value for m in e]),
        default=UserStatus.ACTIVE,
        nullable=False,
    )
    is_email_verified: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
    is_phone_verified: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
    last_login_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
    balance: Mapped[int] = mapped_column(Integer, default=0, nullable=False, comment="Balance in cents")
    full_refund_quota_extra: Mapped[int] = mapped_column(
        Integer, default=0, nullable=False, comment="Extra full-refund quota granted by admin"
    )
    full_refund_quota_reset_at: Mapped[datetime | None] = mapped_column(
        DateTime(timezone=True), nullable=True, comment="Only count full refunds after this time"
    )

    invite_code_change_count: Mapped[int] = mapped_column(
        Integer, default=0, nullable=False, comment="Number of manual invite code changes"
    )
    invite_code_change_extra: Mapped[int] = mapped_column(
        Integer, default=0, nullable=False, comment="Extra invite code change quota granted by admin"
    )

    invite_code: Mapped[str | None] = mapped_column(String(32), unique=True, index=True, nullable=True, comment="用户自己的邀请码")
    bound_agent_id: Mapped[int | None] = mapped_column(BigInteger, nullable=True, index=True, comment="绑定的代理用户ID")

    @property
    def has_password(self) -> bool:
        return self.hashed_password is not None

    @property
    def is_verified(self) -> bool:
        return self.id_card_verified == IdCardVerifiedStatus.VERIFIED.value
