import hashlib
from blake3 import blake3
from blurhash import encode

from tqdm.auto import tqdm

from PIL import Image


def compute_blake3_hash(data, is_file=False, logger=None):
    """
    Compute BLAKE3 hash of a file or string.

    Args:
        data (str): File path (if is_file=True) or raw string.
        is_file (bool): Whether the input is a file path. Defaults to False.
        logger: Optional logger for error messages (e.g., Django `self` or `tqdm`).

    Returns:
        str: BLAKE3 hash or None if an error occurs.
    """
    try:
        hasher = blake3()

        if is_file:
            with open(data, "rb") as f:
                while chunk := f.read(65536):
                    hasher.update(chunk)
        else:
            hasher.update(data.encode())

        return hasher.hexdigest()

    except Exception as e:
        error_message = f"Error computing hash: {e}"

        if logger:
            if hasattr(logger, "style") and hasattr(logger, "stdout"):  # Django command
                logger.stdout.write(logger.style.WARNING(error_message))
            else:  # Default to tqdm
                tqdm.write(error_message)

        return None


# Convenience wrappers for readability
def compute_file_hash_blake3(file_path, logger=None):
    return compute_blake3_hash(file_path, is_file=True, logger=logger)


def compute_string_hash_blake3(string, logger=None):
    return compute_blake3_hash(string, is_file=False, logger=logger)


def compute_md5_hash(file_path):
    """
    Compute the MD5 hash of a file.

    Args:
        file_path (str): Path to the file.

    Returns:
        str: MD5 hash of the file.
    """
    try:
        hash_md5 = hashlib.md5()
        with open(file_path, "rb") as f:
            for chunk in iter(lambda: f.read(4096), b""):
                hash_md5.update(chunk)
        return hash_md5.hexdigest()
    except Exception as e:
        tqdm.write(f"Error computing MD5 hash: {e}")
        return None


def compute_blur_hash(image_path, components_x=4, components_y=4, logger=None):
    """
    Compute the BlurHash of an image.

    Args:
        image_path (str): Path to the image file.
        components_x (int): Number of horizontal components for BlurHash.
        components_y (int): Number of vertical components for BlurHash.
        logger: Optional logger for error messages.

    Returns:
        str: BlurHash string or None if an error occurs.
    """
    try:
        with Image.open(image_path) as img:
            img = img.convert("RGB")  # Ensure it's in RGB mode
            blur_hash = encode(img, components_x, components_y)
            return blur_hash

    except Exception as e:
        error_message = f"Error computing BlurHash: {e}"

        if logger:
            if hasattr(logger, "style") and hasattr(logger, "stdout"):  # Django command
                logger.stdout.write(logger.style.WARNING(error_message))
            else:  # Default to tqdm
                tqdm.write(error_message)

        return None