<?php

declare(strict_types=1);

require_once dirname(__DIR__, 2) . '/core/auth.php';
require_once dirname(__DIR__, 2) . '/core/csrf.php';
require_once dirname(__DIR__, 2) . '/core/validation.php';
require_once dirname(__DIR__, 2) . '/core/audit.php';

function role_module_boot(bool $requirePermissionManagement = false): void
{
    require_login();
    require_permission('manage_roles');

    if ($requirePermissionManagement) {
        require_permission('manage_permissions');
    }
}

function role_list(): array
{
    return db_fetch_all(
        'SELECT r.*, COUNT(DISTINCT rp.permission_id) AS permission_count, COUNT(DISTINCT u.id) AS user_count
         FROM roles r
         LEFT JOIN role_permissions rp ON rp.role_id = r.id
         LEFT JOIN users u ON u.role_id = r.id
         GROUP BY r.id
         ORDER BY r.name ASC'
    );
}

function permission_groups(): array
{
    $groups = [];

    foreach (db_fetch_all('SELECT id, permission_key, permission_name, module_name FROM permissions ORDER BY module_name ASC, permission_name ASC') as $permission) {
        $groups[$permission['module_name']][] = $permission;
    }

    return $groups;
}

function get_role_by_id(int $roleId): ?array
{
    return db_fetch_one('SELECT * FROM roles WHERE id = :id LIMIT 1', ['id' => $roleId]);
}

function find_role_or_abort(int $roleId): array
{
    $role = get_role_by_id($roleId);

    if ($role === null) {
        abort_request(404, 'Role not found', 'The requested role record does not exist.');
    }

    return $role;
}

function role_permission_ids(int $roleId): array
{
    return array_map(
        static fn(array $row): int => (int) $row['permission_id'],
        db_fetch_all('SELECT permission_id FROM role_permissions WHERE role_id = :role_id', ['role_id' => $roleId])
    );
}

function is_system_super_admin_role(array $role): bool
{
    return ($role['name'] ?? '') === 'Super Admin';
}

function validate_role_payload(array $data, array &$errors, ?int $roleId = null): array
{
    validate_required($data, ['name' => 'Role name'], $errors);

    $permissionIds = array_values(array_unique(array_filter(
        array_map('intval', (array) ($data['permission_ids'] ?? [])),
        static fn(int $permissionId): bool => $permissionId > 0
    )));

    $normalized = [
        'name' => trim((string) ($data['name'] ?? '')),
        'description' => trim((string) ($data['description'] ?? '')),
        'permission_ids' => $permissionIds,
    ];

    if ($normalized['name'] !== '' && duplicate_exists('roles', 'name', $normalized['name'], $roleId)) {
        $errors['name'] = 'Role name already exists.';
    }

    if ($normalized['permission_ids'] !== []) {
        $placeholders = implode(',', array_fill(0, count($normalized['permission_ids']), '?'));
        $statement = db()->prepare('SELECT COUNT(*) FROM permissions WHERE id IN (' . $placeholders . ')');
        $statement->execute($normalized['permission_ids']);
        $count = (int) $statement->fetchColumn();

        if ($count !== count($normalized['permission_ids'])) {
            $errors['permission_ids'] = 'One or more selected permissions are invalid.';
        }
    }

    return $normalized;
}

function role_is_in_use(int $roleId): bool
{
    return (int) db_fetch_value('SELECT COUNT(*) FROM users WHERE role_id = :role_id', ['role_id' => $roleId], 0) > 0;
}
