<?php
/**
 * Acciones del Módulo de Roles y Permisos
 */

// Respuestas JSON por defecto
header('Content-Type: application/json');

// Iniciar sesión si no está iniciada
if (session_status() === PHP_SESSION_NONE) {
    session_start();
}

// Definir BASE_PATH si no está definido
if (!defined('BASE_PATH')) {
    define('BASE_PATH', dirname(dirname(__DIR__)));
}

// Incluir configuración y conexión de base de datos
require_once BASE_PATH . '/database/config.php';
require_once BASE_PATH . '/database/connection.php';

// Helper de autenticación si no existe
if (!function_exists('isLoggedIn')) {
    function isLoggedIn() {
        return isset($_SESSION['user_id']) && !empty($_SESSION['user_id']);
    }
}

if (!isLoggedIn()) {
    http_response_code(401);
    echo json_encode(['success' => false, 'message' => 'No autorizado']);
    exit;
}

$db = getDB()->getConnection();
$action = $_GET['action'] ?? '';

switch ($action) {
    case 'create':
        createRole();
        break;
    case 'update':
        updateRole();
        break;
    case 'delete':
        deleteRole();
        break;
    case 'get_permissions':
        getRolePermissions();
        break;
    case 'update_permissions':
        updateRolePermissions();
        break;
    case 'get_users':
        getRoleUsers();
        break;
    case 'assign_user':
        assignUserToRole();
        break;
    case 'remove_user':
        removeUserFromRole();
        break;
    case 'duplicate':
        duplicateRole();
        break;
    case 'get_role_details':
        getRoleDetails();
        break;
    case 'create_permission':
        createPermission();
        break;
    default:
        http_response_code(400);
        echo json_encode(['error' => 'Acción no válida']);
        break;
}

function createRole() {
    global $db;
    
    try {
        $name = $_POST['name'] ?? '';
        $display_name = $_POST['display_name'] ?? '';
        $description = $_POST['description'] ?? '';
        $permissions = $_POST['permissions'] ?? [];
        
        if (empty($name) || empty($display_name)) {
            throw new Exception('Nombre y nombre de visualización son requeridos');
        }
        
        // Verificar que el nombre no exista
        $check_stmt = $db->prepare("SELECT id FROM roles WHERE name = ?");
        $check_stmt->execute([$name]);
        if ($check_stmt->fetch()) {
            throw new Exception('Ya existe un rol con ese nombre');
        }
        
        $db->beginTransaction();
        
        // Crear el rol
        $stmt = $db->prepare("
            INSERT INTO roles (name, display_name, description, created_at) 
            VALUES (?, ?, ?, NOW())
        ");
        $stmt->execute([$name, $display_name, $description]);
        $role_id = $db->lastInsertId();
        
        // Asignar permisos
        if (!empty($permissions)) {
            $perm_stmt = $db->prepare("
                INSERT INTO role_permissions (role_id, permission_id) 
                VALUES (?, ?)
            ");
            
            foreach ($permissions as $permission_id) {
                $perm_stmt->execute([$role_id, $permission_id]);
            }
        }
        
        $db->commit();
        
        echo json_encode([
            'success' => true,
            'message' => 'Rol creado exitosamente',
            'role_id' => $role_id
        ]);
        
    } catch (Exception $e) {
        $db->rollBack();
        http_response_code(400);
        echo json_encode(['error' => $e->getMessage()]);
    }
}

function updateRole() {
    global $db;
    
    try {
        $role_id = $_POST['role_id'] ?? '';
        $display_name = $_POST['display_name'] ?? '';
        $description = $_POST['description'] ?? '';
        
        if (empty($role_id) || empty($display_name)) {
            throw new Exception('ID del rol y nombre de visualización son requeridos');
        }
        
        $stmt = $db->prepare("
            UPDATE roles 
            SET display_name = ?, description = ?, updated_at = NOW() 
            WHERE id = ?
        ");
        $stmt->execute([$display_name, $description, $role_id]);
        
        echo json_encode([
            'success' => true,
            'message' => 'Rol actualizado exitosamente'
        ]);
        
    } catch (Exception $e) {
        http_response_code(400);
        echo json_encode(['error' => $e->getMessage()]);
    }
}

function deleteRole() {
    global $db;
    
    try {
        $role_id = $_POST['role_id'] ?? $_GET['role_id'] ?? '';
        
        if (empty($role_id)) {
            throw new Exception('ID del rol es requerido');
        }
        
        // Verificar que no sea un rol del sistema
        $stmt = $db->prepare("SELECT name FROM roles WHERE id = ?");
        $stmt->execute([$role_id]);
        $role = $stmt->fetch();
        
        if (!$role) {
            throw new Exception('Rol no encontrado');
        }
        
        if (in_array($role['name'], ['admin', 'user', 'manager'])) {
            throw new Exception('No se pueden eliminar roles del sistema');
        }
        
        // Verificar que no tenga usuarios asignados
        $user_check = $db->prepare("SELECT COUNT(*) FROM user_roles WHERE role_id = ?");
        $user_check->execute([$role_id]);
        $user_count = $user_check->fetchColumn();
        
        if ($user_count > 0) {
            throw new Exception('No se puede eliminar un rol que tiene usuarios asignados');
        }
        
        $db->beginTransaction();
        
        // Eliminar permisos del rol
        $perm_stmt = $db->prepare("DELETE FROM role_permissions WHERE role_id = ?");
        $perm_stmt->execute([$role_id]);
        
        // Eliminar el rol
        $role_stmt = $db->prepare("DELETE FROM roles WHERE id = ?");
        $role_stmt->execute([$role_id]);
        
        $db->commit();
        
        echo json_encode([
            'success' => true,
            'message' => 'Rol eliminado exitosamente'
        ]);
        
    } catch (Exception $e) {
        // Hacer rollback solo si hay una transacción activa
        try {
            if ($db instanceof PDO && $db->inTransaction()) {
                $db->rollBack();
            }
        } catch (Exception $rbEx) {
            // Ignorar errores de rollback para no romper la respuesta JSON
        }
        http_response_code(400);
        echo json_encode(['success' => false, 'error' => $e->getMessage()]);
    }
}

function getRolePermissions() {
    global $db;
    
    try {
        $role_id = $_GET['role_id'] ?? '';
        
        if (empty($role_id)) {
            throw new Exception('ID del rol es requerido');
        }
        
        $stmt = $db->prepare("
            SELECT p.id, p.name, p.display_name, p.description, p.module, p.action
            FROM permissions p
            INNER JOIN role_permissions rp ON p.id = rp.permission_id
            WHERE rp.role_id = ?
            ORDER BY p.module, p.action
        ");
        $stmt->execute([$role_id]);
        $permissions = $stmt->fetchAll(PDO::FETCH_ASSOC);
        
        echo json_encode($permissions);
        
    } catch (Exception $e) {
        http_response_code(400);
        echo json_encode(['error' => $e->getMessage()]);
    }
}

function updateRolePermissions() {
    global $db;
    
    try {
        $role_id = $_POST['role_id'] ?? '';
        $permissions = $_POST['permissions'] ?? [];
        
        if (empty($role_id)) {
            throw new Exception('ID del rol es requerido');
        }
        
        $db->beginTransaction();
        
        // Eliminar permisos actuales
        $delete_stmt = $db->prepare("DELETE FROM role_permissions WHERE role_id = ?");
        $delete_stmt->execute([$role_id]);
        
        // Agregar nuevos permisos
        if (!empty($permissions)) {
            $insert_stmt = $db->prepare("
                INSERT INTO role_permissions (role_id, permission_id) 
                VALUES (?, ?)
            ");
            
            foreach ($permissions as $permission_id) {
                $insert_stmt->execute([$role_id, $permission_id]);
            }
        }
        
        $db->commit();
        
        echo json_encode([
            'success' => true,
            'message' => 'Permisos actualizados exitosamente'
        ]);
        
    } catch (Exception $e) {
        $db->rollBack();
        http_response_code(400);
        echo json_encode(['error' => $e->getMessage()]);
    }
}

function createPermission() {
    global $db;
    try {
        $name = $_POST['name'] ?? '';
        $display_name = $_POST['display_name'] ?? '';
        $description = $_POST['description'] ?? '';
        $module = $_POST['module'] ?? '';
        $action = $_POST['action'] ?? $_POST['action_name'] ?? '';
        $assign_role_id = $_POST['assign_role_id'] ?? '';

        if (empty($name) || empty($display_name) || empty($module) || empty($action)) {
            throw new Exception('Nombre, nombre de visualización, módulo y acción son requeridos');
        }

        // Verificar duplicado por nombre técnico
        $check_stmt = $db->prepare('SELECT id FROM permissions WHERE name = ?');
        $check_stmt->execute([$name]);
        if ($check_stmt->fetch()) {
            throw new Exception('Ya existe un permiso con ese nombre técnico');
        }

        // Crear permiso
        $stmt = $db->prepare('
            INSERT INTO permissions (name, display_name, description, module, action, is_system, updated_at)
            VALUES (?, ?, ?, ?, ?, FALSE, NOW())
        ');
        $stmt->execute([$name, $display_name, $description, $module, $action]);
        $perm_id = (int)$db->lastInsertId();

        // Asignar a rol si corresponde
        if (!empty($assign_role_id)) {
            // Verificar rol
            $role_stmt = $db->prepare('SELECT id FROM roles WHERE id = ?');
            $role_stmt->execute([$assign_role_id]);
            if ($role_stmt->fetch()) {
                // Evitar duplicados
                $rp_chk = $db->prepare('SELECT id FROM role_permissions WHERE role_id = ? AND permission_id = ?');
                $rp_chk->execute([$assign_role_id, $perm_id]);
                if (!$rp_chk->fetch()) {
                    $rp_ins = $db->prepare('INSERT INTO role_permissions (role_id, permission_id, granted_at) VALUES (?, ?, NOW())');
                    $rp_ins->execute([$assign_role_id, $perm_id]);
                }
            }
        }

        echo json_encode([
            'success' => true,
            'message' => 'Permiso creado exitosamente',
            'permission_id' => $perm_id
        ]);
    } catch (Exception $e) {
        http_response_code(400);
        echo json_encode(['error' => $e->getMessage()]);
    }
}

function getRoleUsers() {
    global $db;
    
    try {
        $role_id = $_GET['role_id'] ?? '';
        
        if (empty($role_id)) {
            throw new Exception('ID del rol es requerido');
        }
        
        $stmt = $db->prepare("
            SELECT u.id, u.username, u.email, u.first_name, u.last_name, 
                   ur.assigned_at
            FROM users u
            INNER JOIN user_roles ur ON u.id = ur.user_id
            WHERE ur.role_id = ?
            ORDER BY ur.assigned_at DESC
        ");
        $stmt->execute([$role_id]);
        $users = $stmt->fetchAll(PDO::FETCH_ASSOC);
        
        echo json_encode($users);
        
    } catch (Exception $e) {
        http_response_code(400);
        echo json_encode(['error' => $e->getMessage()]);
    }
}

function assignUserToRole() {
    global $db;
    
    try {
        $role_id = $_POST['role_id'] ?? '';
        $user_id = $_POST['user_id'] ?? '';
        
        if (empty($role_id) || empty($user_id)) {
            throw new Exception('ID del rol y del usuario son requeridos');
        }
        
        // Verificar que no esté ya asignado
        $check_stmt = $db->prepare("
            SELECT id FROM user_roles 
            WHERE user_id = ? AND role_id = ?
        ");
        $check_stmt->execute([$user_id, $role_id]);
        
        if ($check_stmt->fetch()) {
            throw new Exception('El usuario ya tiene este rol asignado');
        }
        
        $stmt = $db->prepare("
            INSERT INTO user_roles (user_id, role_id, assigned_at) 
            VALUES (?, ?, NOW())
        ");
        $stmt->execute([$user_id, $role_id]);
        
        echo json_encode([
            'success' => true,
            'message' => 'Usuario asignado al rol exitosamente'
        ]);
        
    } catch (Exception $e) {
        http_response_code(400);
        echo json_encode(['error' => $e->getMessage()]);
    }
}

function removeUserFromRole() {
    global $db;
    
    try {
        $role_id = $_POST['role_id'] ?? '';
        $user_id = $_POST['user_id'] ?? '';
        
        if (empty($role_id) || empty($user_id)) {
            throw new Exception('ID del rol y del usuario son requeridos');
        }
        
        $stmt = $db->prepare("
            DELETE FROM user_roles 
            WHERE user_id = ? AND role_id = ?
        ");
        $stmt->execute([$user_id, $role_id]);
        
        echo json_encode([
            'success' => true,
            'message' => 'Usuario removido del rol exitosamente'
        ]);
        
    } catch (Exception $e) {
        http_response_code(400);
        echo json_encode(['error' => $e->getMessage()]);
    }
}

function duplicateRole() {
    global $db;
    
    try {
        $role_id = $_POST['role_id'] ?? '';
        $new_name = $_POST['new_name'] ?? '';
        $new_display_name = $_POST['new_display_name'] ?? '';
        
        if (empty($role_id) || empty($new_name) || empty($new_display_name)) {
            throw new Exception('Todos los campos son requeridos');
        }
        
        // Verificar que el nuevo nombre no exista
        $check_stmt = $db->prepare("SELECT id FROM roles WHERE name = ?");
        $check_stmt->execute([$new_name]);
        if ($check_stmt->fetch()) {
            throw new Exception('Ya existe un rol con ese nombre');
        }
        
        $db->beginTransaction();
        
        // Obtener datos del rol original
        $original_stmt = $db->prepare("
            SELECT display_name, description 
            FROM roles WHERE id = ?
        ");
        $original_stmt->execute([$role_id]);
        $original = $original_stmt->fetch();
        
        if (!$original) {
            throw new Exception('Rol original no encontrado');
        }
        
        // Crear nuevo rol
        $create_stmt = $db->prepare("
            INSERT INTO roles (name, display_name, description, created_at) 
            VALUES (?, ?, ?, NOW())
        ");
        $create_stmt->execute([
            $new_name, 
            $new_display_name, 
            $original['description'] . ' (Copia)'
        ]);
        $new_role_id = $db->lastInsertId();
        
        // Copiar permisos
        $copy_perms_stmt = $db->prepare("
            INSERT INTO role_permissions (role_id, permission_id)
            SELECT ?, permission_id 
            FROM role_permissions 
            WHERE role_id = ?
        ");
        $copy_perms_stmt->execute([$new_role_id, $role_id]);
        
        $db->commit();
        
        echo json_encode([
            'success' => true,
            'message' => 'Rol duplicado exitosamente',
            'new_role_id' => $new_role_id
        ]);
        
    } catch (Exception $e) {
        $db->rollBack();
        http_response_code(400);
        echo json_encode(['error' => $e->getMessage()]);
    }
}

function getRoleDetails() {
    global $db;
    
    try {
        $role_id = $_GET['role_id'] ?? '';
        
        if (empty($role_id)) {
            throw new Exception('ID del rol es requerido');
        }
        
        // Obtener información del rol
        $role_stmt = $db->prepare("
            SELECT r.*, COUNT(ur.user_id) as user_count
            FROM roles r
            LEFT JOIN user_roles ur ON r.id = ur.role_id
            WHERE r.id = ?
            GROUP BY r.id
        ");
        $role_stmt->execute([$role_id]);
        $role = $role_stmt->fetch(PDO::FETCH_ASSOC);
        
        if (!$role) {
            throw new Exception('Rol no encontrado');
        }
        
        // Obtener permisos del rol
        $perms_stmt = $db->prepare("
            SELECT p.id, p.name, p.display_name, p.module, p.action
            FROM permissions p
            INNER JOIN role_permissions rp ON p.id = rp.permission_id
            WHERE rp.role_id = ?
            ORDER BY p.module, p.action
        ");
        $perms_stmt->execute([$role_id]);
        $permissions = $perms_stmt->fetchAll(PDO::FETCH_ASSOC);
        
        // Obtener usuarios asignados (últimos 5)
        $users_stmt = $db->prepare("
            SELECT u.id, u.username, u.first_name, u.last_name, ur.assigned_at
            FROM users u
            INNER JOIN user_roles ur ON u.id = ur.user_id
            WHERE ur.role_id = ?
            ORDER BY ur.assigned_at DESC
            LIMIT 5
        ");
        $users_stmt->execute([$role_id]);
        $recent_users = $users_stmt->fetchAll(PDO::FETCH_ASSOC);
        
        echo json_encode([
            'role' => $role,
            'permissions' => $permissions,
            'recent_users' => $recent_users
        ]);
        
    } catch (Exception $e) {
        http_response_code(400);
        echo json_encode(['error' => $e->getMessage()]);
    }
}
?>