<?php

declare(strict_types=1);

namespace App\Controllers;

use App\Models\UserModel;
use Core\Auth;
use Core\Request;
use Core\Session;

final class RoleController extends BaseController
{
    private UserModel $model;

    public function __construct()
    {
        parent::__construct();
        $this->model = new UserModel();
    }

    // ── List roles ────────────────────────────────────────────────────────────

    public function index(): void
    {
        Auth::requireLogin();
        if (!Auth::isSuperAdmin()) {
            http_response_code(403);
            $this->view('errors/403', []);
            return;
        }

        $roles = $this->db->fetchAll(
            "SELECT r.id, r.name, r.label,
                    COUNT(rp.permission_id) AS perm_count
               FROM roles r
               LEFT JOIN role_permissions rp ON rp.role_id = r.id
              WHERE r.name != 'customer'
              GROUP BY r.id
              ORDER BY r.id ASC"
        );

        $totalPerms = (int)$this->db->fetchValue("SELECT COUNT(*) FROM permissions");

        $this->view('roles/index', [
            'title'      => 'Roles & Permissions',
            'roles'      => $roles,
            'totalPerms' => $totalPerms,
        ]);
    }

    // ── Create role ───────────────────────────────────────────────────────────

    public function store(): void
    {
        Auth::requireLogin();
        if (!Auth::isSuperAdmin()) { http_response_code(403); exit; }
        Request::verifyCsrf();

        $label = trim(Request::str('label'));
        $name  = strtolower(trim(preg_replace('/\s+/', '_', $label)));

        if ($label === '') {
            Session::flash('error', 'Role name is required.');
            $this->redirect('/roles');
        }

        $exists = $this->db->fetchValue("SELECT id FROM roles WHERE name = ?", [$name]);
        if ($exists) {
            Session::flash('error', "A role named \"{$name}\" already exists.");
            $this->redirect('/roles');
        }

        $this->db->insert('roles', ['name' => $name, 'label' => $label]);
        Session::flash('success', "Role \"{$label}\" created. Assign permissions below.");
        $newId = $this->db->fetchValue("SELECT id FROM roles WHERE name = ?", [$name]);
        $this->redirect('/roles/' . $newId . '/edit');
    }

    // ── Delete role ───────────────────────────────────────────────────────────

    public function delete(array $params = []): void
    {
        Auth::requireLogin();
        if (!Auth::isSuperAdmin()) { http_response_code(403); exit; }
        Request::verifyCsrf();

        $roleId = (int)($params['id'] ?? 0);
        $role   = $this->db->fetchOne("SELECT * FROM roles WHERE id = ?", [$roleId]);
        if (!$role) { $this->redirect('/roles'); }

        $protected = ['super_admin', 'manager', 'kitchen', 'rider', 'customer'];
        if (in_array($role['name'], $protected, true)) {
            Session::flash('error', 'Built-in roles cannot be deleted.');
            $this->redirect('/roles');
        }

        // Check if any users are assigned this role
        $inUse = (int)$this->db->fetchValue("SELECT COUNT(*) FROM users WHERE role_id = ?", [$roleId]);
        if ($inUse > 0) {
            Session::flash('error', "Cannot delete: {$inUse} user(s) are assigned this role.");
            $this->redirect('/roles');
        }

        $this->db->delete('role_permissions', ['role_id' => $roleId]);
        $this->db->delete('roles', ['id' => $roleId]);
        Session::flash('success', "Role \"{$role['label']}\" deleted.");
        $this->redirect('/roles');
    }

    // ── Edit role permissions ─────────────────────────────────────────────────

    public function edit(array $params = []): void
    {
        Auth::requireLogin();
        if (!Auth::isSuperAdmin()) {
            http_response_code(403);
            $this->view('errors/403', []);
            return;
        }

        $roleId = (int)($params['id'] ?? 0);
        $role   = $this->db->fetchOne("SELECT * FROM roles WHERE id = ?", [$roleId]);
        if (!$role) { $this->redirect('/roles'); }

        // All permissions grouped by module
        $allPerms = $this->db->fetchAll(
            "SELECT * FROM permissions ORDER BY module ASC, label ASC"
        );
        $grouped = [];
        foreach ($allPerms as $p) {
            $grouped[$p['module']][] = $p;
        }

        // Currently assigned permission IDs for this role
        $assigned = array_column(
            $this->db->fetchAll("SELECT permission_id FROM role_permissions WHERE role_id = ?", [$roleId]),
            'permission_id'
        );
        $assignedSet = array_flip($assigned);

        $this->view('roles/edit', [
            'title'       => 'Edit Permissions — ' . $role['label'],
            'role'        => $role,
            'grouped'     => $grouped,
            'assignedSet' => $assignedSet,
        ]);
    }

    // ── Save role permissions ─────────────────────────────────────────────────

    public function update(array $params = []): void
    {
        Auth::requireLogin();
        if (!Auth::isSuperAdmin()) {
            http_response_code(403); exit;
        }
        Request::verifyCsrf();

        $roleId = (int)($params['id'] ?? 0);
        $role   = $this->db->fetchOne("SELECT * FROM roles WHERE id = ?", [$roleId]);
        if (!$role) { $this->redirect('/roles'); }

        // super_admin always keeps all permissions — just skip
        if ($role['name'] === 'super_admin') {
            Session::flash('info', 'Super Admin always has all permissions.');
            $this->redirect('/roles');
            return;
        }

        $permIds = array_map('intval', $_POST['permissions'] ?? []);
        $this->model->syncRolePermissions($roleId, $permIds);

        Session::flash('success', 'Permissions for "' . $role['label'] . '" updated.');
        $this->redirect('/roles/' . $roleId . '/edit');
    }
}
