from functools import wraps
from flask import render_template, abort, current_app
from flask_login import current_user

def permission_required(min_level):
    """
    Decorador para verificar nivel de permisos en rutas web.
    
    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 render_template('error.html', 
                                      error_code=403, 
                                      error_message="No tiene permisos suficientes para acceder a esta página."), 403
                
            return f(*args, **kwargs)
        return decorated_function
    return decorator

def project_access_required(access_type='view'):
    """
    Decorador para verificar acceso a un proyecto específico.
    
    Args:
        access_type (str): Tipo de acceso ('view' o 'edit')
        
    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()
            
            # Obtener ID del proyecto de los argumentos
            project_id = kwargs.get('project_id')
            
            if not project_id:
                abort(400, description="ID de proyecto no proporcionado")
            
            # Verificar permisos específicos del proyecto
            from services.project_service import get_project
            
            project = get_project(project_id)
            
            if not project:
                abort(404, description="Proyecto no encontrado")
                
            # Verificar si el proyecto está activo
            if project.get('estado') != 'activo' and not current_user.has_permission(9000):
                return render_template('error.html', 
                                      error_code=403, 
                                      error_message="El proyecto no está activo."), 403
            
            # Verificar permisos específicos
            # Administradores siempre tienen acceso
            if current_user.has_permission(9000):
                return f(*args, **kwargs)
            
            # Verificar permisos en el archivo de permisos del proyecto
            from utils.file_utils import load_json_file
            import os
            
            storage_path = current_app.config['STORAGE_PATH']
            project_dir = os.path.join(storage_path, 'projects', project.get('directory', ''))
            permissions_file = os.path.join(project_dir, 'permissions.json')
            
            permissions = load_json_file(permissions_file, {})
            
            # Verificar permisos específicos del usuario
            user_permissions = permissions.get(current_user.id, {})
            
            if access_type == 'edit' and user_permissions.get('can_edit', False):
                return f(*args, **kwargs)
                
            if access_type == 'view' and user_permissions.get('can_view', False):
                return f(*args, **kwargs)
            
            # Verificar nivel general requerido según el esquema
            schema_code = project.get('esquema')
            
            if not schema_code:
                return render_template('error.html', 
                                      error_code=403, 
                                      error_message="No tiene permisos para acceder a este proyecto."), 403
            
            from services.schema_service import get_schema
            
            schema = get_schema(schema_code)
            
            if not schema:
                return render_template('error.html', 
                                      error_code=403, 
                                      error_message="Esquema no encontrado."), 403
            
            # Nivel mínimo para ver/editar según el esquema
            min_level_view = 0  # Por defecto, cualquier usuario autenticado puede ver
            min_level_edit = 5000  # Por defecto, se requiere nivel de gestor para editar
            
            # Si hay configuración específica en el esquema, usarla
            if 'nivel_ver' in schema:
                min_level_view = schema.get('nivel_ver', 0)
                
            if 'nivel_editar' in schema:
                min_level_edit = schema.get('nivel_editar', 5000)
            
            # Verificar nivel según tipo de acceso
            if access_type == 'edit' and current_user.has_permission(min_level_edit):
                return f(*args, **kwargs)
                
            if access_type == 'view' and current_user.has_permission(min_level_view):
                return f(*args, **kwargs)
            
            # Si llega aquí, no tiene permisos
            return render_template('error.html', 
                                  error_code=403, 
                                  error_message="No tiene permisos para acceder a este proyecto."), 403
                
        return decorated_function
    return decorator

def document_access_required(access_type='view'):
    """
    Decorador para verificar acceso a un documento específico.
    
    Args:
        access_type (str): Tipo de acceso ('view' o 'edit')
        
    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()
            
            # Obtener IDs de proyecto y documento
            project_id = kwargs.get('project_id')
            document_id = kwargs.get('document_id')
            
            if not project_id or not document_id:
                abort(400, description="ID de proyecto o documento no proporcionado")
            
            # Verificar permisos del proyecto primero
            from services.project_service import get_project
            
            project = get_project(project_id)
            
            if not project:
                abort(404, description="Proyecto no encontrado")
                
            # Verificar si el proyecto está activo
            if project.get('estado') != 'activo' and not current_user.has_permission(9000):
                return render_template('error.html', 
                                      error_code=403, 
                                      error_message="El proyecto no está activo."), 403
            
            # Administradores siempre tienen acceso
            if current_user.has_permission(9000):
                return f(*args, **kwargs)
            
            # Obtener información del documento
            from services.document_service import get_document
            
            document = get_document(project_id, document_id)
            
            if not document:
                abort(404, description="Documento no encontrado")
            
            # Obtener el esquema del proyecto
            schema_code = project.get('esquema')
            
            if not schema_code:
                return render_template('error.html', 
                                      error_code=403, 
                                      error_message="No tiene permisos para acceder a este documento."), 403
            
            # Cargar el esquema específico del proyecto
            from utils.file_utils import load_json_file
            import os
            
            storage_path = current_app.config['STORAGE_PATH']
            project_dir = os.path.join(storage_path, 'projects', project.get('directory', ''))
            project_schema_file = os.path.join(project_dir, 'schema.json')
            
            schema = load_json_file(project_schema_file)
            
            if not schema:
                # Si no hay esquema específico, usar el general
                from services.schema_service import get_schema
                schema = get_schema(schema_code)
            
            if not schema:
                return render_template('error.html', 
                                      error_code=403, 
                                      error_message="Esquema no encontrado."), 403
            
            # Obtener el tipo de documento
            document_name = document.get('document_id', '').split('_', 1)[1] if '_' in document.get('document_id', '') else ''
            
            # Buscar configuración de permisos para este tipo de documento
            for doc_type in schema.get('documentos', []):
                if doc_type.get('nombre', '').lower().replace(' ', '_') == document_name:
                    # Verificar nivel según tipo de acceso
                    if access_type == 'edit' and current_user.has_permission(doc_type.get('nivel_editar', 5000)):
                        return f(*args, **kwargs)
                        
                    if access_type == 'view' and current_user.has_permission(doc_type.get('nivel_ver', 0)):
                        return f(*args, **kwargs)
            
            # Si no se encontró configuración específica o no tiene permisos
            return render_template('error.html', 
                                  error_code=403, 
                                  error_message="No tiene permisos para acceder a este documento."), 403
                
        return decorated_function
    return decorator
