import hashlib
from datetime import datetime, timedelta
from typing import Union, Any
import jwt
import os
from src.config import base_config

ACCESS_TOKEN_EXPIRE_MINUTES = 30  # 30 minutes
REFRESH_TOKEN_EXPIRE_MINUTES = 60 * 24 * 7  # 7 days
settings = base_config.get_settings()
ALGORITHM = settings.jwt_algorithm
JWT_SECRET_KEY = settings.jwt_token  # should be kept secret
JWT_REFRESH_SECRET_KEY = settings.jwt_refresh_token  # should be kept se


def create_access_token(subject: Union[str, Any], expires_delta: int = None) -> str:
    if expires_delta is not None:
        expires_delta = datetime.utcnow() + expires_delta
    else:
        expires_delta = datetime.utcnow() + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)

    to_encode = {"exp": expires_delta, "sub": str(subject)}
    encoded_jwt = jwt.encode(to_encode, JWT_SECRET_KEY, ALGORITHM)
    return encoded_jwt


def create_refresh_token(subject: Union[str, Any], expires_delta: int = None) -> str:
    if expires_delta is not None:
        expires_delta = datetime.utcnow() + expires_delta
    else:
        expires_delta = datetime.utcnow() + timedelta(minutes=REFRESH_TOKEN_EXPIRE_MINUTES)

    to_encode = {"exp": expires_delta, "sub": str(subject)}
    encoded_jwt = jwt.encode(to_encode, JWT_REFRESH_SECRET_KEY, ALGORITHM)
    return encoded_jwt


"""
Password context 
"""
from passlib.context import CryptContext

password_context = CryptContext(schemes=["bcrypt"], deprecated="auto")


def get_hashed_password(password: str) -> str:
    return password_context.hash(password)


def verify_password(password: str, hashed_pass: str) -> bool:
    return hash_password(password) == hashed_pass


def hash_password(input_string):
    return sha256_hash(sha1_hash(input_string))


def sha1_hash(input_string):
    """
    Computes the SHA-1 hash of the given input string and returns it as a hexadecimal string.

    :param input_string: String to hash.
    :return: SHA-1 hash of input_string as a hexadecimal string.
    """
    return __hash(input_string, hashlib.sha1())


def sha256_hash(input_string):
    """
    Computes the SHA-256 hash of the given input string and returns it as a hexadecimal string.

    :param input_string: String to hash.
    :return: SHA-256 hash of input_string as a hexadecimal string.
    """
    return __hash(input_string, hashlib.sha256())


def __hash(input_string, hash_obj):
    # Encode the input string to bytes
    input_bytes = input_string.encode('utf-8')
    # Update the hash object with the bytes of the input string
    hash_obj.update(input_bytes)
    # Get the hexadecimal representation of the digest
    hex_dig = hash_obj.hexdigest()
    return hex_dig
