<?php
if (!class_exists('RoleController')) {
class RoleController extends Controller
{
    private array $builtIn = [
        'super_admin','admin','developer',
        'manager','hr_manager','cashier',
        'stock_keeper','accountant'
    ];

    // ── List ─────────────────────────────────────────────────
    public function index(): void
    {
        Auth::requirePermission('users.view');

        // Keep the list query compatible with MySQL and MariaDB installations
        // that use strict GROUP BY settings.
        $roles = Database::fetchAll(
            "SELECT r.*,
                    (SELECT COUNT(*)
                       FROM users u
                      WHERE u.role_id = r.id
                        AND u.status = 'active') AS user_count,
                    (SELECT COUNT(*)
                       FROM role_permissions rp
                      WHERE rp.role_id = r.id) AS perm_count
               FROM roles r
              ORDER BY r.id ASC"
        );

        // Normalize old database values such as `Manager`, `Stock Keeper`,
        // and `Super Admin` without requiring an immediate database migration.
        foreach ($roles as &$roleRow) {
            $roleRow['role_name'] = strtolower(
                str_replace(' ', '_', trim((string)$roleRow['role_name']))
            );
        }
        unset($roleRow);

        $permissions = Database::fetchAll(
            "SELECT id, module, action, permission_key
               FROM permissions
              ORDER BY module ASC, action ASC"
        );

        $rolePermMap = [];
        $mappings = Database::fetchAll(
            "SELECT role_id, permission_id
               FROM role_permissions
              ORDER BY role_id ASC, permission_id ASC"
        );

        foreach ($mappings as $rp) {
            $roleId = (int)$rp['role_id'];
            if (!isset($rolePermMap[$roleId])) {
                $rolePermMap[$roleId] = [];
            }
            $rolePermMap[$roleId][] = (int)$rp['permission_id'];
        }

        $permsByModule = [];
        foreach ($permissions as $permission) {
            $module = (string)$permission['module'];
            if (!isset($permsByModule[$module])) {
                $permsByModule[$module] = [];
            }
            $permsByModule[$module][] = $permission;
        }

        $pageTitle = 'Roles & Permissions';
        $breadcrumb = [
            ['label' => 'Users', 'url' => APP_URL . '/users'],
            ['label' => 'Roles']
        ];

        ob_start();
        require APP_PATH . '/views/users/roles.php';
        $content = ob_get_clean();

        require APP_PATH . '/views/layouts/main.php';
    }

    // ── Create form ───────────────────────────────────────────
    public function create(): void
    {
        Auth::requirePermission('users.create');

        $permissions   = Database::fetchAll("SELECT * FROM permissions ORDER BY module, action");
        $permsByModule = [];
        foreach ($permissions as $p) { $permsByModule[$p['module']][] = $p; }
        $roles     = Database::fetchAll("SELECT id, role_name FROM roles ORDER BY role_name");
        $role      = null;
        $rolePerms = [];

        $pageTitle  = 'Create Role';
        $breadcrumb = [['label'=>'Users','url'=>APP_URL.'/users'],['label'=>'Roles','url'=>APP_URL.'/roles'],['label'=>'Create']];
        ob_start(); require APP_PATH.'/views/users/role_form.php';
        $content = ob_get_clean();
        require APP_PATH.'/views/layouts/main.php';
    }

    // ── Store ─────────────────────────────────────────────────
    public function store(): void
    {
        Auth::requirePermission('users.create');
        Auth::requireCsrf();

        $name     = strtolower(trim(preg_replace('/[^a-z_]/','', $this->post('role_name',''))));
        $desc     = trim($this->post('description',''));
        $copyFrom = (int)$this->post('copy_from', 0);
        $perms    = (array)$this->post('permissions',[]);

        if (!$name) {
            redirectWith(APP_URL.'/roles/create','error','Role name is required.');
            return;
        }

        try {
            Database::execute(
                'INSERT INTO roles (role_name, description) VALUES (?, ?)',
                [$name, $desc ?: null]
            );
            $roleId = (int)Database::fetchColumn('SELECT LAST_INSERT_ID()');

            if ($copyFrom > 0 && empty($perms)) {
                $perms = array_column(
                    Database::fetchAll('SELECT permission_id FROM role_permissions WHERE role_id=?',[$copyFrom]),
                    'permission_id'
                );
            }
            $this->savePermissions($roleId, $perms);

            redirectWith(APP_URL.'/roles/edit/'.$roleId,'success',"Role \"{$name}\" created — now set permissions.");
        } catch (\PDOException $e) {
            redirectWith(APP_URL.'/roles/create','error','Role name already exists.');
        }
    }

    // ── Edit form ─────────────────────────────────────────────
    public function edit(string $id): void
    {
        Auth::requirePermission('users.edit');

        $role = Database::fetchOne('SELECT * FROM roles WHERE id=?',[(int)$id]);
        if (!$role) { redirectWith(APP_URL.'/roles','error','Role not found.'); return; }

        $role['user_count'] = (int)Database::fetchColumn(
            "SELECT COUNT(*) FROM users WHERE role_id=? AND status='active'",[(int)$id]
        );

        $permissions   = Database::fetchAll("SELECT * FROM permissions ORDER BY module, action");
        $permsByModule = [];
        foreach ($permissions as $p) { $permsByModule[$p['module']][] = $p; }

        $rolePerms = array_column(
            Database::fetchAll('SELECT permission_id FROM role_permissions WHERE role_id=?',[(int)$id]),
            'permission_id'
        );

        $pageTitle  = 'Edit Role — '.ucfirst(str_replace('_',' ',$role['role_name']));
        $breadcrumb = [['label'=>'Roles','url'=>APP_URL.'/roles'],['label'=>'Edit']];
        ob_start(); require APP_PATH.'/views/users/role_form.php';
        $content = ob_get_clean();
        require APP_PATH.'/views/layouts/main.php';
    }

    // ── Update ────────────────────────────────────────────────
    public function update(string $id): void
    {
        Auth::requirePermission('users.edit');
        Auth::requireCsrf();

        $roleId = (int)$id;
        $role   = Database::fetchOne('SELECT * FROM roles WHERE id=?',[$roleId]);
        if (!$role) {
            redirectWith(APP_URL.'/roles','error','Role not found.');
            return;
        }

        // Keep name for built-ins, allow custom name for others
        if (in_array($role['role_name'], $this->builtIn, true)) {
            $name = $role['role_name'];
        } else {
            $name = strtolower(trim(preg_replace('/[^a-z_]/','', $this->post('role_name', $role['role_name']))));
            if (!$name) { $name = $role['role_name']; }
        }

        $desc  = trim($this->post('description',''));

        // ── Step 1: Update role info ──────────────────────────
        Database::execute(
            'UPDATE roles SET role_name=?, description=? WHERE id=?',
            [$name, $desc !== '' ? $desc : null, $roleId]
        );

        // ── Step 2: Read submitted permissions ────────────────
        $submitted = $_POST['permissions'] ?? [];
        $perms     = is_array($submitted) ? array_map('intval', $submitted) : [];

        // ── Step 3: Save permissions ──────────────────────────
        $saved = $this->savePermissions($roleId, $perms);

        // ── Step 4: Bump perms_version ────────────────────────
        $this->bumpPermsVersion($roleId);

        // ── Step 5: Refresh own session if needed ─────────────
        if ((int)($_SESSION['role_id'] ?? 0) === $roleId) {
            $this->refreshSession($roleId);
        }

        Auth::logAudit(Auth::id(),'role_update','roles',"Role \"{$name}\": {$saved} permissions saved");
        redirectWith(
            APP_URL.'/roles/edit/'.$roleId,
            'success',
            "✅ Role \"{$name}\" updated — {$saved} permissions saved."
        );
    }

    // ── Delete ────────────────────────────────────────────────
    public function delete(string $id): void
    {
        Auth::requirePermission('users.delete');
        Auth::requireCsrf();

        $roleId = (int)$id;
        $role   = Database::fetchOne('SELECT * FROM roles WHERE id=?',[$roleId]);
        if (!$role) { redirectWith(APP_URL.'/roles','error','Role not found.'); return; }

        if (in_array($role['role_name'], $this->builtIn, true)) {
            redirectWith(APP_URL.'/roles','error',"Cannot delete built-in role \"{$role['role_name']}\".");
            return;
        }

        $userCount = (int)Database::fetchColumn('SELECT COUNT(*) FROM users WHERE role_id=?',[$roleId]);
        if ($userCount > 0) {
            redirectWith(APP_URL.'/roles','error',"Cannot delete — {$userCount} user(s) assigned. Reassign first.");
            return;
        }

        Database::execute('DELETE FROM role_permissions WHERE role_id=?',[$roleId]);
        Database::execute('DELETE FROM roles WHERE id=?',[$roleId]);
        redirectWith(APP_URL.'/roles','success',"Role \"{$role['role_name']}\" deleted.");
    }

    // ── Private: Save permissions ─────────────────────────────
    private function savePermissions(int $roleId, array $permIds): int
    {
        // 1. Delete all existing for this role
        Database::execute('DELETE FROM role_permissions WHERE role_id=?', [$roleId]);

        // 2. Insert each selected permission
        $count = 0;
        foreach ($permIds as $pid) {
            $pid = (int)$pid;
            if ($pid <= 0) continue;
            try {
                Database::execute(
                    'INSERT INTO role_permissions (role_id, permission_id) VALUES (?,?)
                     ON DUPLICATE KEY UPDATE role_id=role_id',
                    [$roleId, $pid]
                );
                $count++;
            } catch (\Exception $e) {}
        }
        return $count;
    }

    // ── Private: Bump perms_version ───────────────────────────
    private function bumpPermsVersion(int $roleId): void
    {
        // Try with both columns first
        try {
            Database::execute(
                "UPDATE roles SET
                    perms_version   = COALESCE(perms_version,0) + 1,
                    perms_updated_at = NOW()
                 WHERE id = ?",
                [$roleId]
            );
            return;
        } catch (\Exception $e) {}

        // Try with only perms_version
        try {
            Database::execute(
                "UPDATE roles SET perms_version = COALESCE(perms_version,0) + 1 WHERE id = ?",
                [$roleId]
            );
        } catch (\Exception $e) {}
    }

    // ── Private: Refresh session ──────────────────────────────
    private function refreshSession(int $roleId): void
    {
        try {
            $perms = array_column(
                Database::fetchAll(
                    'SELECT p.permission_key FROM role_permissions rp
                     JOIN permissions p ON p.id=rp.permission_id
                     WHERE rp.role_id=?', [$roleId]
                ),
                'permission_key'
            );
            $version = (int)Database::fetchColumn(
                'SELECT COALESCE(perms_version,1) FROM roles WHERE id=?', [$roleId]
            );
            $_SESSION['permissions']  = $perms;
            $_SESSION['perms_version'] = $version;
        } catch (\Exception $e) {}
    }
} // end RoleController
} // end class_exists