<?php
declare(strict_types=1);

namespace App\Controllers;

require_once BASE_PATH . '/app/helpers/permissions.php';

use App\Core\Controller;
use App\Core\Database;

final class AdminRbacController extends Controller
{
    private function ensureTables($db): void
    {
        $t1 = (int)$db->query("SELECT COUNT(*) FROM information_schema.tables WHERE table_schema=DATABASE() AND table_name='roles'")->fetchColumn();
        $t2 = (int)$db->query("SELECT COUNT(*) FROM information_schema.tables WHERE table_schema=DATABASE() AND table_name='users'")->fetchColumn();
        if ($t1 <= 0) throw new \RuntimeException("roles table missing");
        if ($t2 <= 0) throw new \RuntimeException("users table missing");
    }

    public function index(): void
    {
        require_admin_area();
        $db = Database::getInstance();
        $this->ensureTables($db);

        $rq = trim((string)($_GET['rq'] ?? ''));
        $uq = trim((string)($_GET['uq'] ?? ''));

        // roles
        $roles = [];
        if ($rq !== '') {
            $st = $db->prepare("SELECT * FROM roles WHERE name LIKE :q OR code LIKE :q ORDER BY id ASC");
            $st->execute([':q'=>'%'.$rq.'%']);
            $roles = $st->fetchAll() ?: [];
        } else {
            $roles = $db->query("SELECT * FROM roles ORDER BY id ASC")->fetchAll() ?: [];
        }

        // edit role
        $editRole = null;
        $reid = (int)($_GET['edit_role'] ?? 0);
        if ($reid > 0) {
            $st = $db->prepare("SELECT * FROM roles WHERE id=:id LIMIT 1");
            $st->execute([':id'=>$reid]);
            $editRole = $st->fetch() ?: null;
        }

        // users list + role names
        $users = [];
        if ($uq !== '') {
            $st = $db->prepare("
              SELECT u.*, r.name AS role_name, r.code AS role_code
              FROM users u
              LEFT JOIN roles r ON r.id=u.role_id
              WHERE u.email LIKE :q OR u.first_name LIKE :q OR u.last_name LIKE :q
              ORDER BY u.id DESC
              LIMIT 300
            ");
            $st->execute([':q'=>'%'.$uq.'%']);
            $users = $st->fetchAll() ?: [];
        } else {
            $users = $db->query("
              SELECT u.*, r.name AS role_name, r.code AS role_code
              FROM users u
              LEFT JOIN roles r ON r.id=u.role_id
              ORDER BY u.id DESC
              LIMIT 200
            ")->fetchAll() ?: [];
        }

        $this->view('admin/rbac/index', compact('roles','users','editRole','rq','uq'));
    }

    public function roleSave(): void
    {
        require_admin_area();
        $db = Database::getInstance();
        $this->ensureTables($db);

        if (($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'POST') { http_response_code(405); return; }

        $id = (int)($_POST['id'] ?? 0);
        $name = trim((string)($_POST['name'] ?? ''));
        $code = trim((string)($_POST['code'] ?? ''));

        if ($name === '' || $code === '') {
            if (function_exists('flash_set')) flash_set('danger', 'Missing name/code');
            header('Location: '.base_path('admin/rbac'));
            exit;
        }

        // normalize code
        $code = strtolower(preg_replace('/[^a-z0-9_]+/','_', $code) ?? $code);

        if ($id > 0) {
            $db->prepare("UPDATE roles SET name=:n, code=:c WHERE id=:id")->execute([':n'=>$name, ':c'=>$code, ':id'=>$id]);
            if (function_exists('flash_set')) flash_set('success', 'Role updated');
        } else {
            $db->prepare("INSERT INTO roles(name, code) VALUES(:n,:c)")->execute([':n'=>$name, ':c'=>$code]);
            if (function_exists('flash_set')) flash_set('success', 'Role added');
        }

        header('Location: '.base_path('admin/rbac'));
        exit;
    }

    public function roleDelete(): void
    {
        require_admin_area();
        $db = Database::getInstance();
        $this->ensureTables($db);

        $id = (int)($_GET['id'] ?? 0);
        if ($id <= 0) { header('Location: '.base_path('admin/rbac')); exit; }

        // prevent deleting superadmin role
        $code = (string)($db->prepare("SELECT code FROM roles WHERE id=:id")->execute([':id'=>$id]) ? '' : '');
        $st = $db->prepare("SELECT code FROM roles WHERE id=:id LIMIT 1");
        $st->execute([':id'=>$id]);
        $code = (string)($st->fetchColumn() ?: '');

        if ($code === 'superadmin') {
            if (function_exists('flash_set')) flash_set('warning', 'Cannot delete superadmin role');
            header('Location: '.base_path('admin/rbac'));
            exit;
        }

        // Unassign users from this role
        $db->prepare("UPDATE users SET role_id=1 WHERE role_id=:rid")->execute([':rid'=>$id]); // fallback to role_id=1 (superadmin) only if needed
        // Better: set to author if exists; keep simple to avoid breaking
        $db->prepare("DELETE FROM roles WHERE id=:id")->execute([':id'=>$id]);

        if (function_exists('flash_set')) flash_set('success', 'Role deleted (users reassigned)');
        header('Location: '.base_path('admin/rbac'));
        exit;
    }

    public function assignUserRole(): void
    {
        require_admin_area();
        $db = Database::getInstance();
        $this->ensureTables($db);

        if (($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'POST') { http_response_code(405); return; }

        $uid = (int)($_POST['user_id'] ?? 0);
        $rid = (int)($_POST['role_id'] ?? 0);
        if ($uid <= 0 || $rid <= 0) {
            if (function_exists('flash_set')) flash_set('danger', 'Missing user/role');
            header('Location: '.base_path('admin/rbac'));
            exit;
        }

        $db->prepare("UPDATE users SET role_id=:r WHERE id=:u")->execute([':r'=>$rid, ':u'=>$uid]);
        if (function_exists('flash_set')) flash_set('success', 'User role updated');

        header('Location: '.base_path('admin/rbac'));
        exit;
    }
}
