import time
import uuid
import json
import base64
import hashlib
from datetime import datetime

from app.config.settings import Config  
from app.models.blacklist import Blacklist

class TokenService:
    @staticmethod
    # Function to generate token for a user based on the token type
    def generate_token(email, token_type, expiration_time_in_hours=4):
        """
        Generate a token.

        Args:
            email (str): The email associated with the token.
            token_type (str): The type of the token.
            expiration_time_in_hours (int, optional): The expiration time of the token in hours. Defaults to 4 hours.

        Returns:
            str: The generated token.
        """
        data = {
            "email": email,
            "type": token_type,
            "exp": int(time.time()) + expiration_time_in_hours * 3600
        }

        json_data = json.dumps(data)
        encoded_data = json_data.encode("utf-8")
        signature = hashlib.sha1(encoded_data + Config.SECRET_KEY.encode("utf-8")).hexdigest()
        token_data = encoded_data + b"-_-" + signature.encode("utf-8")
        return base64.urlsafe_b64encode(token_data).rstrip(b"=").decode("utf-8")

    @staticmethod
    # Function to verify generated token with SHA-128 and no padding
    def verify_token(token):
        """
        Verify the validity and expiration of an activation token.

        Args:
            token (str): The token to be verified.

        Returns:
            Tuple[bool, Union[str, str]]: A tuple containing a boolean indicating whether
            the token is valid and either the associated email or an error message.

        Note:
            This function decodes and verifies tokens by checking its signature and 
            expiration time. If the token is valid and not expired, it returns True 
            and the associated . If the token is valid but expired, it returns False 
            and an error message. If an exception occurs during the verification 
            process, it returns False and an error message.

        """
        try:
            # Decode the activation token from base64 without padding
            decoded_token = base64.urlsafe_b64decode(token.encode("utf-8") + b"==") 

            # Split the decoded token into encoded data and signature
            encoded_data, signature = decoded_token.split(b"-_-")

            # Compute the signature of the encoded data
            computed_signature = hashlib.sha1(encoded_data + Config().SECRET_KEY.encode("utf-8")).hexdigest()

            # Compare the computed signature with the extracted signature
            if computed_signature == signature.decode("utf-8"):
                
                # Token is valid
                token_data = json.loads(encoded_data.decode("utf-8"))
                
                if token_data["exp"] >= int(time.time()):
                    # Token is not expired, return True and the associated data
                    return True, token_data
                else:
                    # Token has expired, return False and an error message
                    return False, "Token has expired" 
                
            # Token is valid, but an error occurred during the process
            return True, encoded_data
        except Exception as e:
            # An exception occurred during token verification, return False and the error message
            return False, str(e)
 
    @staticmethod
    def is_blacklisted(user, jti):
        """
        Check if a token is blacklisted (revoked).

        Args:
            token (str): The token to check.

        Returns:
            bool: True if the token is blacklisted, False if not.
        """  
        return Blacklist.objects(user=user, jti=jti).first() is not None
    
    @staticmethod
    def blacklist_token(token, token_type, user, jti, reason):
        """
        Blacklist a token with a given reason.

        Args:
            token (str): The token to blacklist.
            token_type (str): The type of token (e.g., 'access' or 'refresh').
            user (User): The user associated with the token.
            jti (str): The unique JWT ID (if applicable).
            reason (str): The reason for blacklisting (e.g., 'expired' or 'revoked').

        Returns:
            bool: True if the token is successfully blacklisted, False if not.
        """ 
        blacklist_entry = Blacklist(
            public_id =str(uuid.uuid4()),
            token=token,
            token_type=token_type,
            user=user,
            jti=jti,
            reason=reason,
            revoked_at=datetime.utcnow()
        )
        blacklist_entry.save()