from django.db import models
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager


class UserManager(BaseUserManager):
    """ The user Manager is what takes care of creating objects for the User model class.
        This can be customized with any fields later on

    Raises:
        ValueError: If required params are not provided
    """

    def create(self, username, pid, first_name, last_name, email, password=None):
        """Creates a user in the User table

        Args:
            pid (int): Primary key that is also the panther ID
            first_name (str): First Name
            last_name (str): Last Name
            password (str): Provided password. Defaults to None.

        Raises:
            ValueError: If required params are not provided

        Returns:
            User: User object
        """
        if not username or not pid or not first_name or not last_name:
            raise ValueError('Required parameters missing')

        user = self.model(
            username=username,
            pid=pid,
            first_name=first_name,
            last_name=last_name,
        )

        # if the email field is not null
        if email:
            user.email = self.normalize_email(email)

        # if the password wasn't passed, create a default one
        # First letter of first_name - PID - first letter of last_name
        if not password:
            password = user.gen_default_password()

        # because passwords need to be hashed, use the default method to save passwords
        user.set_password(password)
        user.save(using=self._db)
        return user

    # simply use the method before and set is_admin to true
    def create_superuser(self, username, pid, first_name, last_name, email=None, password=None):
        """Simply create a s uperuser by changing the default is_admin to True

        Returns:
            User: User object
        """
        user = self.create(username, pid, first_name,
                           last_name, email, password)
        user.is_admin = True
        user.save(using=self._db)
        return user


class User(AbstractBaseUser):
    """A class that inherits from the AbstractBaseUser, which 
    create a User model.This User model defines a 
    datastore entity.
    This class is ordering by User.pid.

    Args:
        AbstractBaseUser (_type_): AbstractBaseUser class

    Returns:
        _type_: sting object (User.pid, User.last_name, and User.first_names)
    """
    username = models.CharField(max_length=20, unique=True, primary_key=True)
    pid = models.IntegerField()
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)
    email = models.EmailField(
        max_length=50, verbose_name='Email address', null=True, blank=True)
    password = models.CharField(max_length=128, null=True)

    is_admin = models.BooleanField(default=False)
    is_active = models.BooleanField(default=True)

    # ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.permission', verbose_name='user permissions')),

    # required fields for an AbstractBaseUser
    REQUIRED_FIELDS = ['pid', 'first_name', 'last_name']
    USERNAME_FIELD = 'username'

    # use the custom user manager
    objects = UserManager()

    def gen_default_password(self):
        return str(self.first_name).lower()[0] + str(self.pid) + str(self.last_name).lower()[0]

    def set_default_password(self):
        self.set_password(self.gen_default_password())

    # after calling this method, call save() to hit the database
    def update_fields(self, validated_data):
        self.pid = validated_data.get('pid', self.pid)
        self.first_name = validated_data.get('first_name', self.first_name)
        self.last_name = validated_data.get('last_name', self.last_name)
        self.email = validated_data.get('email', self.email)

    # allow to check for permissions
    def has_perm(self, perm, obj=None):
        # THIS NEEDS TO BE IMPLEMENTED
        return True

    def has_module_perms(self, app_label):
        # check if the user has permissions to view the 'app_label'
        return True

    # can add as many properties as we want, depending on the fields
    # that will be used later on
    @property
    def is_staff(self):
        return self.is_admin

    def __str__(self) -> str:
        return f'{self.pid} - {self.first_name} {self.last_name}'

    class Meta:
        ordering = ['pid']
