# (c) cavaliba.com - app_data - crypto
# V3.28

import base64
import hashlib
import secrets


def _derive_key(key, salt):
    """Derive a longer key from user key + salt using PBKDF2"""
    return hashlib.pbkdf2_hmac('sha256', key.encode('utf-8'), salt, 10000)


def string_encode(key, clear):
    """
    Simple symmetric encryption with randomization.
    Returns base64-encoded encrypted string.
    """
    salt = secrets.token_bytes(16)
    derived_key = _derive_key(key, salt)

    enc = []
    clear_bytes = clear.encode('utf-8')

    for i in range(len(clear_bytes)):
        key_byte = derived_key[i % len(derived_key)]
        enc_byte = clear_bytes[i] ^ key_byte
        enc.append(enc_byte)

    result = salt + bytes(enc)
    return base64.urlsafe_b64encode(result).decode('utf-8')


def string_decode(key, enc):
    """
    Decrypt base64-encoded encrypted string.
    Returns original cleartext.
    """
    data = base64.urlsafe_b64decode(enc.encode('utf-8'))

    salt = data[:16]
    encrypted = data[16:]

    derived_key = _derive_key(key, salt)

    dec = []
    for i in range(len(encrypted)):
        key_byte = derived_key[i % len(derived_key)]
        dec_byte = encrypted[i] ^ key_byte
        dec.append(dec_byte)

    return bytes(dec).decode('utf-8')


def hash_create(clear, algo='sha256', iterations=10000):
    """
    Create a one-way hash of the cleartext.
    Returns a string in format: $ALGO$SALT$HEXVALUE$

    Args:
        clear: The cleartext string to hash
        algo: Algorithm name (default: pbkdf2_sha256)
        iterations: Number of PBKDF2 iterations (default: 10000)

    Returns:
        String in format $pbkdf2_sha256$10000$SALT_HEX$HASH_HEX$
    """
    if not clear:
        return None

    salt = secrets.token_bytes(16)
    salt_hex = salt.hex()


    if algo == 'sha256':
        hash_bytes = hashlib.sha256((salt_hex + clear).encode('utf-8')).digest()
        hash_hex = hash_bytes.hex()
        return f"${algo}${salt_hex}${hash_hex}$"

    # elif algo == 'pbkdf2_sha256':
    #     hash_bytes = hashlib.pbkdf2_hmac('sha256', clear.encode('utf-8'), salt, iterations)
    #     hash_hex = hash_bytes.hex()
    #     return f"${algo}${iterations}${salt_hex}${hash_hex}$"


    return None


def hash_check(clear, hashed):
    """
    Verify if cleartext matches the hashed value.

    Args:
        clear: The cleartext string to verify
        hashed: The hash string in format $ALGO$SALT$HEXVALUE$

    Returns:
        True if match, False otherwise
    """
    if not clear or not hashed:
        return False

    parts = hashed.strip('$').split('$')

    if len(parts) < 3:
        return False

    algo = parts[0]

    if algo == 'sha256' and len(parts) == 3:
        salt_hex = parts[1]
        expected_hash = parts[2]

        hash_bytes = hashlib.sha256((salt_hex + clear).encode('utf-8')).digest()
        computed_hash = hash_bytes.hex()

        return computed_hash == expected_hash


    # elif algo == 'pbkdf2_sha256' and len(parts) == 4:
    #     iterations = int(parts[1])
    #     salt_hex = parts[2]
    #     expected_hash = parts[3]

    #     salt = bytes.fromhex(salt_hex)
    #     hash_bytes = hashlib.pbkdf2_hmac('sha256', clear.encode('utf-8'), salt, iterations)
    #     computed_hash = hash_bytes.hex()

    #     return computed_hash == expected_hash

    return False



# Usage example:
# from app_home.configuration import get_configuration
# key = get_configuration("env", "CAVALIBA_CIPHER_KEY")
# if key:
#     encrypted = string_encode(key, "my secret message")
#     decrypted = string_decode(key, encrypted)


    # key = get_configuration("env","CAVALIBA_CIPHER_KEY")
    # if key:
    #     entry.content = string_encode(key, sms)
