from uuid import uuid4

from django.contrib.auth.models import AbstractUser
from django.contrib.auth.models import Group as BaseGroup
from django.core.cache import cache
from django.db.models import (
    BooleanField,
    CharField,
    EmailField,
    ImageField,
    JSONField,
    UUIDField,
)
from django.utils.translation import gettext_lazy as _
from rest_framework_simplejwt.token_blacklist.models import (
    BlacklistedToken as BaseBlacklistedToken,
)
from rest_framework_simplejwt.token_blacklist.models import (
    OutstandingToken as BaseOutstandingToken,
)

from core.abstract import NiceModel
from evibes.settings import LANGUAGE_CODE, LANGUAGES
from vibes_auth.managers import UserManager
from vibes_auth.validators import validate_phone_number


class User(AbstractUser, NiceModel):  # type: ignore [django-manager-missing]
    __doc__ = _(
        "Represents a User entity with customized fields and methods for extended functionality. "  # type: ignore
        "This class extends the AbstractUser model and integrates additional features like "
        "custom email login, validation methods, subscription status, verification, and "
        "attributes storage. It also provides utilities for managing recently viewed items and "
        "token-based activation for verifying accounts. The User model is designed to handle "
        "specific use cases for enhanced user management."
    )

    def get_uuid_as_path(self, *args):
        return "users/" + str(self.uuid) + "/" + args[0]

    email = EmailField(_("email"), unique=True, help_text=_("user email address"))
    phone_number = CharField(
        _("phone_number"),
        max_length=20,
        unique=True,
        blank=True,
        null=True,
        help_text=_("user phone number"),
        validators=[
            validate_phone_number,
        ],
    )
    username: None = None  # type: ignore [assignment]
    first_name = CharField(_("first_name"), max_length=150, blank=True, null=True)  # type: ignore [assignment]
    last_name = CharField(_("last_name"), max_length=150, blank=True, null=True)  # type: ignore [assignment]
    avatar = ImageField(
        null=True,
        verbose_name=_("avatar"),
        upload_to=get_uuid_as_path,
        blank=True,
        help_text=_("user profile image"),
    )

    is_verified = BooleanField(
        default=False,
        verbose_name=_("is verified"),
        help_text=_("user verification status"),
    )
    is_active = BooleanField(
        _("is_active"),
        default=False,
        help_text=_("unselect this instead of deleting accounts"),
    )
    is_subscribed = BooleanField(
        verbose_name=_("is_subscribed"), help_text=_("user's newsletter subscription status"), default=False
    )

    activation_token = UUIDField(default=uuid4, verbose_name=_("activation token"))
    language = CharField(choices=LANGUAGES, default=LANGUAGE_CODE, null=False, blank=False, max_length=7)
    attributes = JSONField(verbose_name=_("attributes"), default=dict, blank=True, null=True)

    USERNAME_FIELD = "email"
    REQUIRED_FIELDS = []
    # noinspection PyClassVar
    objects = UserManager()  # type: ignore [misc, assignment]

    def add_to_recently_viewed(self, product_uuid):
        recently_viewed = self.recently_viewed
        if product_uuid not in recently_viewed:
            if not len(recently_viewed) >= 48:
                recently_viewed.append(product_uuid)
                cache.set(f"user_{self.uuid}_rv", recently_viewed)
            else:
                recently_viewed.pop(0)
                recently_viewed.append(product_uuid)
                cache.set(f"user_{self.uuid}_rv", recently_viewed)

    @property
    def recently_viewed(self):
        return cache.get(f"user_{self.uuid}_rv", [])

    def check_token(self, token):
        return str(token) == str(self.activation_token)

    def __str__(self):
        return self.email

    class Meta:
        swappable = "AUTH_USER_MODEL"
        verbose_name = _("user")
        verbose_name_plural = _("users")


class Group(BaseGroup):
    """
    Proxy model representing a Group entity.

    This class acts as a proxy for the `BaseGroup` model, providing additional
    configuration for display and usage purposes. It does not introduce new fields
    or behavior but alters representation and metadata for the Group model.

    Attributes:
        Meta.proxy (bool): Indicates this is a proxy model.
        Meta.verbose_name (str): Human-readable singular name for the Group model.
        Meta.verbose_name_plural (str): Human-readable plural name for the Group
                                        model.
    """

    class Meta:
        proxy = True
        verbose_name = _("group")
        verbose_name_plural = _("groups")


class OutstandingToken(BaseOutstandingToken):
    """
    Represents a proxy model for outstanding tokens.

    This class is a proxy for the `BaseOutstandingToken` model, used to manage
    and customize behaviors or configurations related to outstanding tokens.
    It does not add additional fields or logic to the base model but allows for
    overloading or extending its default functionality as required.

    """

    class Meta:
        proxy = True
        verbose_name = _("outstanding token")
        verbose_name_plural = _("outstanding tokens")


class BlacklistedToken(BaseBlacklistedToken):
    """
    Represents a blacklisted token model in the system.

    This class acts as a Django model proxy and serves the purpose of managing
    blacklisted tokens. It inherits from a base class provided for this purpose,
    allowing for the extension of functionality or customization of behavior
    without altering the original base class's structure. It also defines the
    Meta options for the model, affecting its database and administrative
    representation.

    """

    class Meta:
        proxy = True
        verbose_name = _("blacklisted token")
        verbose_name_plural = _("blacklisted tokens")
