from datetime import datetime
from mongoengine import StringField, EmailField, DateTimeField, BooleanField, ListField, ReferenceField, CASCADE

from app.config.extensions import bcrypt
from app.models import Base
 
class User(Base):
    """
    Professional User model for managing user information.

    Attributes:
        username (str): The unique username of the user (required).
        email (str): The email address of the user (required, unique).
        password (str): The user's password (required).
        first_name (str): The user's first name.
        last_name (str): The user's last name. 
        is_verified (bool): A flag indicating if the user's email is verified.
        is_superuser (bool): A flag indicating if the user is a superuser.
        is_admin (bool): A flag indicating if the user is an admin.
        is_active (bool): A flag indicating if the user account is active.
        is_staff (bool): A flag indicating if the user is staff.
        last_login (datetime): The date and time of the user's last login.
        date_joined (datetime): The date and time of user registration (auto-generated).
        roles (list of Role): User roles or permissions (related to Role model).
        last_seen_at (datetime): The date and time when the user was last seen.
        notif_enabled (bool): A flag indicating if notifications are enabled for the user.
        is_online (bool): A flag indicating if the user is currently online.
        is_blocked (bool): A flag indicating if the user is blocked.

    Methods:
        __str__(): Return the username as a string representation of the user.
        set_password(password: str): Set the user's password (typically after hashing).
        check_password(password: str): Check if the provided password matches the user's password.
        add_role(role: Role): Add a role to the user's list of roles.
        remove_role(role: Role): Remove a role from the user's list of roles.
        mark_as_online(): Mark the user as online.
        mark_as_offline(): Mark the user as offline.
        block_user(): Block the user, preventing certain actions.
        unblock_user(): Unblock the user, allowing them to resume normal activities.
        update_last_seen(): Update the user's last seen timestamp to the current time.

    """

    username     = StringField(
        required=True, 
        unique=True, 
        max_length=50, help_text="The unique username of the user."
    )
    email        = EmailField(
        required=True, 
        unique=True, 
        help_text="The email address of the user."
    )
    password     = StringField(
        required=True, 
        help_text="The user's password."
    )

    company_name = StringField(
        max_length=150, 
        help_text="The user's Company name."
    )
    company_type = StringField(
        required=True,  
        max_length=150, 
        choices=["Anonymous Company", "Brands Company", "Ad Agency Company", "TV Channels Company"],
        help_text="The user's Company type."
    )
    
    role         = StringField(
        max_length=50, 
        help_text="The user's rols."
    )
    is_verified  = BooleanField(
        default=False, 
        help_text="A flag indicating if the user's email is verified."
    )
    is_superuser = BooleanField(
        default=False, 
        help_text="A flag indicating if the user is a superuser."
    )
    is_admin     = BooleanField(
        default=False, 
        help_text="A flag indicating if the user is an admin."
    )
    is_active    = BooleanField(
        default=True, 
        help_text="A flag indicating if the user account is active."
    )
    is_staff     = BooleanField(
        default=False, 
        help_text="A flag indicating if the user is staff."
    )
    is_online    = BooleanField(
        default=False, 
        help_text="A flag indicating if the user is currently online."
    )
    is_blocked   = BooleanField(
        default=False, 
        help_text="A flag indicating if the user is blocked."
    )

    notif_enabled = BooleanField(
        default=True, 
        help_text="A flag indicating if notifications are enabled for the user."
    )

    last_login   = DateTimeField(
        default=None, 
        help_text="The date and time of the user's last login."
    )
    date_joined  = DateTimeField(
        default=datetime.utcnow, 
        readonly=True, 
        help_text="The date and time of user registration"
    )
    last_seen_at = DateTimeField(
        default=None, 
        help_text="The date and time when the user was last seen."
    )
 
    def __str__(self):
        """
        Return the username as a string representation of the user.

        Returns:  
            str: The username of the user.
        """
        return self.username

    def set_password(self, password: str):
        """
        Set the user's password, typically after hashing it.

        Args:
            password (str): The user's password.

        Returns:
            None
        """
        self.password = bcrypt.generate_password_hash(password).decode('utf-8')

    def check_password(self, password: str):
        """
        Check if the provided password matches the user's password.

        Args:
            password (str): The password to check.

        Returns:
            bool: True if the password matches, False otherwise.
        """
        return bcrypt.check_password_hash(self.password, password)  
  
    def mark_as_online(self):
        """
        Mark the user as online.

        Returns:
            None
        """
        self.is_online = True

    def mark_as_offline(self):
        """
        Mark the user as offline.

        Returns:
            None
        """
        self.is_online = False

    def block_user(self):
        """
        Block the user, preventing them from certain actions.

        Returns:
            None
        """
        self.is_blocked = True

    def unblock_user(self):
        """
        Unblock the user, allowing them to resume normal activities.

        Returns:
            None
        """
        self.is_blocked = False

    def update_last_seen(self):
        """
        Update the user's last seen timestamp to the current time.

        Returns:
            None
        """
        self.last_seen_at = datetime.utcnow()

    def update_last_login(self):
        """
        Update the user's last login timestamp to the current time.

        Returns:
            None
        """
        self.last_login = datetime.utcnow()

    def to_dict(self):
        """
        Convert the document to a dictionary.
        """ 
        user_dict = super(User, self).to_dict()
        
        exclude_fields = ['id', 'password', 'is_online', '_cls', 'roles']
            
        if not user_dict.get('deleted', False):
            user_dict.pop('deleted', None) 
            user_dict.pop('deleted_at', None)

        user_dict['date_joined'] = self._format_datetime(user_dict.get('date_joined'))
        user_dict['last_login'] = self._format_datetime(user_dict.get('last_login'))
        user_dict['last_seen_at'] = self._format_datetime(user_dict.get('last_seen_at')) 
          
        return user_dict