<?php

declare(strict_types=1);

/**
 * Ave Fénix
 * Gestión de roles y permisos.
 */

require_once __DIR__ . '/init.php';

/*
|--------------------------------------------------------------------------
| Protección de acceso
|--------------------------------------------------------------------------
*/

if (!tiene_permiso('gestionar_roles')) {
    if (isset($_REQUEST['action'])) {
        header(
            'Content-Type: application/json; charset=utf-8'
        );

        http_response_code(403);

        echo json_encode([
            'success' => false,
            'message' =>
                'No tienes permiso para administrar roles.',
        ], JSON_UNESCAPED_UNICODE);

        exit;
    }

    $_SESSION['flash_message'] = [
        'type' => 'error',
        'text' =>
            'No tienes permiso para acceder a Roles y permisos.',
    ];

    header('Location: index.php');
    exit;
}

/* AFENIXX-ROLES-SECURITY-20260724 */

if (
    empty($_SESSION['csrf_gestionar_roles'])
    || !is_string(
        $_SESSION['csrf_gestionar_roles']
    )
) {
    $_SESSION['csrf_gestionar_roles'] =
        bin2hex(random_bytes(32));
}

$csrfRolesToken =
    $_SESSION['csrf_gestionar_roles'];

function af_roles_json(
    array $payload,
    int $statusCode = 200
): void {
    if (!headers_sent()) {
        header(
            'Content-Type: application/json; charset=utf-8'
        );

        http_response_code($statusCode);
    }

    echo json_encode(
        $payload,
        JSON_UNESCAPED_UNICODE
        | JSON_UNESCAPED_SLASHES
    );

    exit;
}

/*
|--------------------------------------------------------------------------
| Acciones AJAX
|--------------------------------------------------------------------------
*/

if (isset($_REQUEST['action'])) {
    $action = trim(
        (string) ($_REQUEST['action'] ?? '')
    );

    if ($action === 'get_role_permissions') {
        if (
            ($_SERVER['REQUEST_METHOD'] ?? 'GET')
            !== 'GET'
        ) {
            af_roles_json([
                'success' => false,
                'message' =>
                    'Método de solicitud no permitido.',
            ], 405);
        }

        $roleId = filter_input(
            INPUT_GET,
            'id_rol',
            FILTER_VALIDATE_INT
        );

        if (!$roleId || $roleId < 1) {
            af_roles_json([
                'success' => false,
                'message' =>
                    'El rol seleccionado no es válido.',
            ], 422);
        }

        try {
            $roleStatement = $pdo->prepare(
                'SELECT id, nombre_rol
                 FROM roles
                 WHERE id = ?
                 LIMIT 1'
            );

            $roleStatement->execute([$roleId]);

            $role = $roleStatement->fetch(
                PDO::FETCH_ASSOC
            );

            if (!$role) {
                af_roles_json([
                    'success' => false,
                    'message' =>
                        'El rol seleccionado no existe.',
                ], 404);
            }

            $permissionStatement = $pdo->prepare(
                'SELECT id_permiso
                 FROM rol_permiso
                 WHERE id_rol = ?
                 ORDER BY id_permiso ASC'
            );

            $permissionStatement->execute([$roleId]);

            $assignedPermissions = array_map(
                'intval',
                $permissionStatement->fetchAll(
                    PDO::FETCH_COLUMN
                )
            );

            af_roles_json([
                'success' => true,
                'role' => [
                    'id' => (int) $role['id'],
                    'name' =>
                        (string) $role['nombre_rol'],
                ],
                'assigned_permissions' =>
                    $assignedPermissions,
            ]);
        } catch (Throwable $exception) {
            error_log(
                '[gestionar_roles] Consultar rol '
                . $roleId
                . ': '
                . $exception->getMessage()
            );

            af_roles_json([
                'success' => false,
                'message' =>
                    'No se pudieron cargar los permisos.',
            ], 500);
        }
    }

    if ($action === 'save_role_permissions') {
        if (
            ($_SERVER['REQUEST_METHOD'] ?? 'GET')
            !== 'POST'
        ) {
            af_roles_json([
                'success' => false,
                'message' =>
                    'Método de solicitud no permitido.',
            ], 405);
        }

        $receivedToken = trim(
            (string) (
                $_POST['csrf_token'] ?? ''
            )
        );

        if (
            $receivedToken === ''
            || !hash_equals(
                $csrfRolesToken,
                $receivedToken
            )
        ) {
            af_roles_json([
                'success' => false,
                'message' =>
                    'La sesión de seguridad venció. '
                    . 'Recarga la página.',
            ], 419);
        }

        $roleId = filter_input(
            INPUT_POST,
            'id_rol',
            FILTER_VALIDATE_INT
        );

        if (!$roleId || $roleId < 1) {
            af_roles_json([
                'success' => false,
                'message' =>
                    'El rol seleccionado no es válido.',
            ], 422);
        }

        $permissionIds =
            $_POST['permission_ids'] ?? [];

        if (!is_array($permissionIds)) {
            $permissionIds = [];
        }

        $permissionIds = array_values(
            array_unique(
                array_filter(
                    array_map(
                        'intval',
                        $permissionIds
                    ),
                    static fn (
                        int $permissionId
                    ): bool =>
                        $permissionId > 0
                )
            )
        );

        try {
            $roleStatement = $pdo->prepare(
                'SELECT id, nombre_rol
                 FROM roles
                 WHERE id = ?
                 LIMIT 1'
            );

            $roleStatement->execute([$roleId]);

            $role = $roleStatement->fetch(
                PDO::FETCH_ASSOC
            );

            if (!$role) {
                af_roles_json([
                    'success' => false,
                    'message' =>
                        'El rol seleccionado no existe.',
                ], 404);
            }

            $roleName = trim(
                (string) $role['nombre_rol']
            );

            if (
                (int) $role['id'] === 1
                || strcasecmp(
                    $roleName,
                    'Superadmin'
                ) === 0
            ) {
                af_roles_json([
                    'success' => false,
                    'message' =>
                        'Los permisos del Superadmin '
                        . 'no pueden modificarse.',
                ], 403);
            }

            /*
             * Conservar solamente permisos que existan
             * realmente en la base de datos.
             */
            $validPermissionIds = [];

            if ($permissionIds !== []) {
                $placeholders = implode(
                    ',',
                    array_fill(
                        0,
                        count($permissionIds),
                        '?'
                    )
                );

                $validStatement = $pdo->prepare(
                    "SELECT id
                     FROM permisos
                     WHERE id IN ($placeholders)"
                );

                $validStatement->execute(
                    $permissionIds
                );

                $validPermissionIds = array_map(
                    'intval',
                    $validStatement->fetchAll(
                        PDO::FETCH_COLUMN
                    )
                );
            }

            /*
             * Mis Referidos es exclusivamente personal
             * del rol Admin.
             */
            if (
                strcasecmp(
                    $roleName,
                    'Admin'
                ) !== 0
            ) {
                $referralStatement = $pdo->prepare(
                    "SELECT id
                     FROM permisos
                     WHERE clave_permiso =
                        'ver_referidos_propios_admin'
                     LIMIT 1"
                );

                $referralStatement->execute();

                $referralPermissionId = (int) (
                    $referralStatement->fetchColumn()
                    ?: 0
                );

                if ($referralPermissionId > 0) {
                    $validPermissionIds =
                        array_values(
                            array_filter(
                                $validPermissionIds,
                                static fn (
                                    int $permissionId
                                ): bool =>
                                    $permissionId
                                    !== $referralPermissionId
                            )
                        );
                }
            }

            $pdo->beginTransaction();

            $deleteStatement = $pdo->prepare(
                'DELETE FROM rol_permiso
                 WHERE id_rol = ?'
            );

            $deleteStatement->execute([$roleId]);

            if ($validPermissionIds !== []) {
                $insertStatement = $pdo->prepare(
                    'INSERT INTO rol_permiso
                        (id_rol, id_permiso)
                     VALUES
                        (?, ?)'
                );

                foreach (
                    $validPermissionIds
                    as $permissionId
                ) {
                    $insertStatement->execute([
                        $roleId,
                        $permissionId,
                    ]);
                }
            }

            $pdo->commit();

            af_roles_json([
                'success' => true,
                'message' =>
                    'Los permisos fueron guardados correctamente.',
            ]);
        } catch (Throwable $exception) {
            if ($pdo->inTransaction()) {
                $pdo->rollBack();
            }

            error_log(
                '[gestionar_roles] Guardar rol '
                . $roleId
                . ': '
                . $exception->getMessage()
            );

            af_roles_json([
                'success' => false,
                'message' =>
                    'No se pudieron guardar los permisos.',
            ], 500);
        }
    }

    af_roles_json([
        'success' => false,
        'message' =>
            'La acción solicitada no existe.',
    ], 404);
}

/*
|--------------------------------------------------------------------------
| Cargar la página
|--------------------------------------------------------------------------
*/

$current_page = basename(
    $_SERVER['PHP_SELF']
);

$nombre_usuario_logueado =
    $_SESSION['admin']['nombre_usuario']
    ?? 'Usuario';

$error_message_db = '';
$roles = [];
$permisos = [];

try {
    $roles = $pdo->query(
        'SELECT id, nombre_rol
         FROM roles
         ORDER BY id ASC'
    )->fetchAll(PDO::FETCH_ASSOC);

    $permisos = $pdo->query(
        "SELECT
            id,
            clave_permiso,
            COALESCE(
                NULLIF(descripcion, ''),
                clave_permiso
            ) AS descripcion
         FROM permisos
         ORDER BY descripcion ASC"
    )->fetchAll(PDO::FETCH_ASSOC);
} catch (Throwable $exception) {
    error_log(
        '[gestionar_roles] Cargar página: '
        . $exception->getMessage()
    );

    $error_message_db =
        'No se pudieron cargar los roles y permisos.';
}

$titulo_pagina =
    'Gestionar Roles y Permisos';

require_once __DIR__ . '/admin_header.php';
require_once __DIR__
    . '/includes/superadmin_ui_helpers.php';
?>

<div class="sa-page">
    <?php
    sa_render_module_hero([
        'icon' => 'fa-user-shield',
        'eyebrow' => 'SEGURIDAD Y PERMISOS',
        'title' => 'Roles y permisos',
        'description' => '',
        'count' => count($roles),
    ]);

    sa_render_summary_cards([
        [
            'label' => 'Roles',
            'value' => count($roles),
            'icon' => 'fa-user-tag',
            'hint' => 'Perfiles administrativos',
        ],
        [
            'label' => 'Permisos disponibles',
            'value' => count($permisos),
            'icon' => 'fa-key',
            'tone' => 'is-blue',
            'hint' => 'Acciones configurables',
        ],
        [
            'label' => 'Rol protegido',
            'value' => 'Superadmin',
            'icon' => 'fa-shield-halved',
            'tone' => 'is-amber',
            'hint' => 'Acceso total del sistema',
        ],
    ]);
    ?>

    <?php if ($error_message_db !== ''): ?>
        <div class="sa-alert sa-alert--danger">
            <i class="fas fa-triangle-exclamation"></i>

            <div>
                <?= sa_e($error_message_db) ?>
            </div>
        </div>
    <?php endif; ?>

    <section class="sa-split-layout">
        <article class="sa-card">
            <header class="sa-card__header">
                <div>
                    <h2>Roles del sistema</h2>

                    <p>
                        Selecciona un rol para revisar
                        sus permisos.
                    </p>
                </div>

                <span class="sa-records-panel__icon">
                    <i class="fas fa-user-tag"></i>
                </span>
            </header>

            <div class="sa-card__body">
                <div
                    id="lista-roles"
                    class="sa-role-list"
                >
                    <?php foreach ($roles as $rol): ?>
                        <button
                            type="button"
                            class="sa-role-option"
                            data-id-rol="<?= (int) $rol['id'] ?>"
                            data-nombre-rol="<?= sa_e(
                                (string) $rol['nombre_rol']
                            ) ?>"
                        >
                            <span>
                                <i class="fas fa-user-tag"></i>

                                <?= sa_e(
                                    (string) $rol['nombre_rol']
                                ) ?>
                            </span>

                            <?php if (
                                (int) $rol['id'] === 1
                            ): ?>
                                <small>
                                    <i class="fas fa-lock"></i>
                                    Protegido
                                </small>
                            <?php else: ?>
                                <i class="fas fa-chevron-right"></i>
                            <?php endif; ?>
                        </button>
                    <?php endforeach; ?>
                </div>
            </div>
        </article>

        <article class="sa-card">
            <header class="sa-card__header">
                <div>
                    <h2>
                        Permisos del rol:
                        <span
                            id="nombre-rol-seleccionado"
                            style="color:var(--sa-primary)"
                        >
                            Ninguno
                        </span>
                    </h2>

                    <p>
                        Los cambios se aplican después
                        de guardarlos.
                    </p>
                </div>

                <button
                    id="guardar-permisos-btn"
                    type="button"
                    class="sa-btn sa-btn--primary"
                    disabled
                >
                    <i class="fas fa-floppy-disk"></i>
                    Guardar cambios
                </button>
            </header>

            <div class="sa-card__body">
                <div class="sa-alert sa-alert--info">
                    <i class="fas fa-circle-info"></i>

                    <div>
                        Selecciona un rol de la izquierda.
                        Superadmin tiene acceso total.
                    </div>
                </div>

                <div
                    id="lista-permisos"
                    class="sa-permissions-grid"
                >
                    <div class="sa-empty-state">
                        <i class="fas fa-hand-pointer"></i>
                        <strong>Selecciona un rol</strong>

                        <span>
                            Sus permisos aparecerán aquí.
                        </span>
                    </div>
                </div>
            </div>
        </article>
    </section>
</div>

<script>
$(document).ready(function () {
    'use strict';

    let selectedRoleId = null;
    let selectedRoleName = '';

    const csrfRolesToken = <?= json_encode(
        $csrfRolesToken,
        JSON_UNESCAPED_SLASHES
        | JSON_HEX_TAG
        | JSON_HEX_AMP
        | JSON_HEX_APOS
        | JSON_HEX_QUOT
    ) ?>;

    const allPermissions = <?= json_encode(
        $permisos,
        JSON_UNESCAPED_UNICODE
        | JSON_UNESCAPED_SLASHES
        | JSON_HEX_TAG
        | JSON_HEX_AMP
        | JSON_HEX_APOS
        | JSON_HEX_QUOT
    ) ?>;

    function escapeHtml(value) {
        return $('<div>')
            .text(value ?? '')
            .html();
    }

    function showError(message) {
        Swal.fire({
            title: 'No se pudo completar',
            text:
                message
                || 'Ocurrió un problema inesperado.',
            icon: 'error',
            confirmButtonColor: '#dc2626'
        });
    }

    function fetchAndRenderPermissions(
        roleId,
        roleName
    ) {
        $('#lista-permisos').html(`
            <div class="sa-empty-state">
                <i class="fas fa-spinner fa-spin"></i>
                <strong>Cargando permisos</strong>
                <span>Espera un momento…</span>
            </div>
        `);

        $.ajax({
            url: 'gestionar_roles.php',
            method: 'GET',
            dataType: 'json',
            data: {
                action: 'get_role_permissions',
                id_rol: roleId
            }
        })
        .done(function (response) {
            if (
                !response
                || response.success !== true
            ) {
                showError(
                    response && response.message
                        ? response.message
                        : 'No se pudieron cargar los permisos.'
                );

                return;
            }

            renderPermissions(
                response.assigned_permissions || [],
                roleId,
                roleName
            );
        })
        .fail(function (xhr) {
            const response =
                xhr.responseJSON || {};

            showError(
                response.message
                || 'No se pudo comunicar con el servidor.'
            );
        });
    }

    function renderPermissions(
        assignedPermissions,
        roleId,
        roleName
    ) {
        const assignedSet = new Set(
            (assignedPermissions || []).map(Number)
        );

        const normalizedRoleName = String(
            roleName || ''
        )
        .trim()
        .toLocaleLowerCase('es');

        const isSuperadmin =
            Number(roleId) === 1
            || normalizedRoleName === 'superadmin';

        const isAdmin =
            normalizedRoleName === 'admin';

        let permissionsHtml = '';

        allPermissions.forEach(function (permission) {
            const permissionId =
                Number(permission.id);

            const permissionKey =
                String(
                    permission.clave_permiso || ''
                );

            const permissionDescription =
                String(
                    permission.descripcion
                    || permissionKey
                    || 'Permiso'
                );

            const isAdminReferral =
                permissionKey
                === 'ver_referidos_propios_admin';

            const disabledByRole =
                isAdminReferral && !isAdmin;

            const checked =
                isSuperadmin
                || (
                    !disabledByRole
                    && assignedSet.has(permissionId)
                );

            let helpText = permissionKey;

            if (isAdminReferral) {
                helpText = isAdmin
                    ? 'Permite abrir el módulo personal Mis Referidos.'
                    : 'Disponible únicamente para el rol Admin.';
            }

            permissionsHtml += `
                <label
                    class="sa-permission-option"
                    for="perm-${permissionId}"
                >
                    <input
                        id="perm-${permissionId}"
                        name="permissions[]"
                        type="checkbox"
                        value="${permissionId}"
                        ${checked ? 'checked' : ''}
                        ${
                            isSuperadmin || disabledByRole
                                ? 'disabled'
                                : ''
                        }
                    >

                    <span class="sa-permission-check">
                        <i class="fas fa-check"></i>
                    </span>

                    <span>
                        <strong>
                            ${escapeHtml(permissionDescription)}
                        </strong>

                        <small
                            style="
                                display:block;
                                margin-top:4px;
                                color:#94a3b8;
                                font-size:10px;
                            "
                        >
                            ${escapeHtml(helpText)}
                        </small>
                    </span>
                </label>
            `;
        });

        if (permissionsHtml === '') {
            permissionsHtml = `
                <div class="sa-empty-state">
                    <i class="fas fa-key"></i>
                    <strong>No existen permisos</strong>
                    <span>
                        Ejecuta la migración SQL
                        para registrar los módulos.
                    </span>
                </div>
            `;
        }

        $('#lista-permisos').html(
            permissionsHtml
        );

        if (isSuperadmin) {
            $('#lista-permisos').append(`
                <div
                    class="
                        sa-alert
                        sa-alert--warning
                        sa-permission-note
                    "
                >
                    <i class="fas fa-lock"></i>

                    <div>
                        Superadmin recibe todos los permisos
                        automáticamente y no puede modificarse.
                    </div>
                </div>
            `);
        }

        $('#guardar-permisos-btn').prop(
            'disabled',
            isSuperadmin
        );
    }

    $('#lista-roles').on(
        'click',
        '.sa-role-option',
        function () {
            $('#lista-roles .sa-role-option')
                .removeClass('is-active');

            $(this).addClass('is-active');

            selectedRoleId = Number(
                $(this).data('id-rol')
            );

            selectedRoleName = String(
                $(this).data('nombre-rol') || ''
            );

            $('#nombre-rol-seleccionado').text(
                selectedRoleName
            );

            fetchAndRenderPermissions(
                selectedRoleId,
                selectedRoleName
            );
        }
    );

    $('#guardar-permisos-btn').on(
        'click',
        function () {
            if (
                !selectedRoleId
                || selectedRoleId === 1
            ) {
                Swal.fire({
                    title: 'Selecciona un rol',
                    text:
                        'Selecciona un rol modificable.',
                    icon: 'warning',
                    confirmButtonColor: '#dc2626'
                });

                return;
            }

            const selectedPermissions = [];

            $('#lista-permisos input[type="checkbox"]:checked')
                .not(':disabled')
                .each(function () {
                    selectedPermissions.push(
                        Number($(this).val())
                    );
                });

            const button = $(this);

            button.prop('disabled', true);

            Swal.fire({
                title: 'Guardando permisos',
                text: 'Espera un momento…',
                allowOutsideClick: false,
                didOpen: function () {
                    Swal.showLoading();
                }
            });

            $.ajax({
                url: 'gestionar_roles.php',
                method: 'POST',
                dataType: 'json',
                data: {
                    action:
                        'save_role_permissions',
                    csrf_token:
                        csrfRolesToken,
                    id_rol:
                        selectedRoleId,
                    permission_ids:
                        selectedPermissions
                }
            })
            .done(function (response) {
                if (
                    !response
                    || response.success !== true
                ) {
                    showError(
                        response && response.message
                            ? response.message
                            : 'No se pudieron guardar los permisos.'
                    );

                    return;
                }

                Swal.fire({
                    title: 'Permisos actualizados',
                    text: response.message,
                    icon: 'success',
                    confirmButtonColor: '#dc2626'
                });

                fetchAndRenderPermissions(
                    selectedRoleId,
                    selectedRoleName
                );
            })
            .fail(function (xhr) {
                const response =
                    xhr.responseJSON || {};

                showError(
                    response.message
                    || 'No se pudo comunicar con el servidor.'
                );
            })
            .always(function () {
                button.prop('disabled', false);
            });
        }
    );
});
</script>

<?php require_once __DIR__ . '/admin_footer.php'; ?>

<!-- AFENIXX-V12-ASSETS -->
<link rel="stylesheet" href="../assets/css/afenixx_v12.css?v=2026.07.24-v12">
<script src="../assets/js/afenixx_v12.js?v=2026.07.24-v12"></script>
