import os
import hashlib
import re
from flask import current_app, request, abort
from functools import wraps
from flask_login import current_user
from werkzeug.utils import secure_filename

# Try to import magic with a fallback for Windows
try:
    import magic

    HAS_MAGIC = True
except ImportError:
    HAS_MAGIC = False
    current_app.logger.warning("libmagic not found, using basic file type detection")

from utils.file_utils import detect_file_type


def check_file_type(file_stream, allowed_mime_types):
    """
    Verificar el tipo MIME real de un archivo.

    Args:
        file_stream: Stream del archivo a verificar
        allowed_mime_types (list): Lista de tipos MIME permitidos

    Returns:
        bool: True si el tipo es permitido, False en caso contrario
    """
    # Guardar posición actual en el stream
    current_position = file_stream.tell()

    # Leer los primeros bytes para detectar el tipo
    file_head = file_stream.read(2048)
    file_stream.seek(current_position)  # Restaurar posición

    # Detectar tipo MIME
    mime = magic.Magic(mime=True)
    file_type = mime.from_buffer(file_head)

    return file_type in allowed_mime_types


def calculate_checksum(file_path):
    """
    Calcular el hash SHA-256 de un archivo.

    Args:
        file_path (str): Ruta al archivo

    Returns:
        str: Hash SHA-256 en formato hexadecimal
    """
    sha256_hash = hashlib.sha256()

    with open(file_path, "rb") as f:
        # Leer por bloques para archivos grandes
        for byte_block in iter(lambda: f.read(4096), b""):
            sha256_hash.update(byte_block)

    return sha256_hash.hexdigest()


def sanitize_filename(filename):
    """
    Sanitizar nombre de archivo.

    Args:
        filename (str): Nombre de archivo original

    Returns:
        str: Nombre de archivo sanitizado
    """
    # Primero usar secure_filename de Werkzeug
    safe_name = secure_filename(filename)

    # Eliminar caracteres problemáticos adicionales
    safe_name = re.sub(r"[^\w\s.-]", "", safe_name)

    # Reemplazar espacios por guiones bajos
    safe_name = safe_name.replace(" ", "_")

    return safe_name


def generate_unique_filename(base_dir, filename_pattern):
    """
    Generar nombre de archivo único basado en un patrón.

    Args:
        base_dir (str): Directorio base
        filename_pattern (str): Patrón de nombre (puede contener {counter})

    Returns:
        str: Nombre de archivo único
    """
    counter = 1
    filename = filename_pattern.format(counter=counter)

    while os.path.exists(os.path.join(base_dir, filename)):
        counter += 1
        filename = filename_pattern.format(counter=counter)

    return filename


def permission_required(min_level):
    """
    Decorador para verificar nivel de permisos.

    Args:
        min_level (int): Nivel mínimo requerido

    Returns:
        function: Decorador configurado
    """

    def decorator(f):
        @wraps(f)
        def decorated_function(*args, **kwargs):
            if not current_user.is_authenticated:
                return current_app.login_manager.unauthorized()

            if not current_user.has_permission(min_level):
                return forbidden_error()

            return f(*args, **kwargs)

        return decorated_function

    return decorator


def forbidden_error():
    """Respuesta para error 403 (acceso denegado)."""
    from flask import render_template

    return (
        render_template("error.html", error_code=403, error_message="Acceso denegado"),
        403,
    )
