<?php
require_once __DIR__ . '/../../includes/bootstrap.php';
require_login();

$pageTitle = 'Role Permissions';

if (!function_exists('h')) {
    function h($value): string { return htmlspecialchars((string)$value, ENT_QUOTES, 'UTF-8'); }
}
if (!function_exists('rp_flash')) {
    function rp_flash(string $type, string $message): void {
        $_SESSION['role_permissions_flash'][] = ['type' => $type, 'message' => $message];
    }
}
if (!function_exists('rp_get_flash')) {
    function rp_get_flash(): array {
        $items = $_SESSION['role_permissions_flash'] ?? [];
        unset($_SESSION['role_permissions_flash']);
        return $items;
    }
}
if (!function_exists('rp_current_role')) {
    function rp_current_role(): string {
        if (function_exists('current_user_role')) return strtolower((string)current_user_role());
        return strtolower((string)($_SESSION['role'] ?? $_SESSION['user_role'] ?? $_SESSION['type'] ?? 'user'));
    }
}
if (!function_exists('rp_is_admin')) {
    function rp_is_admin(): bool {
        return in_array(rp_current_role(), ['super_admin','admin','owner'], true);
    }
}
if (!function_exists('rp_table_exists')) {
    function rp_table_exists(PDO $pdo, string $table): bool {
        $stmt = $pdo->prepare("SELECT COUNT(*) FROM information_schema.tables WHERE table_schema=DATABASE() AND table_name=:t");
        $stmt->execute([':t' => $table]);
        return (int)$stmt->fetchColumn() > 0;
    }
}
if (!function_exists('rp_role_landing_page')) {
    /**
     * Return the configured landing path (site-relative) for a role, or '' if
     * none is set. Safe to call from the login flow:
     *
     *   $path = rp_role_landing_page($pdo, $roleKey);
     *   header('Location: ' . BASE_URL . ($path !== '' ? $path : '/modules/dashboard/index.php'));
     */
    function rp_role_landing_page(PDO $pdo, string $roleKey): string {
        $roleKey = strtolower(trim($roleKey));
        if ($roleKey === '') return '';
        try {
            // Guard against older schemas without the column.
            $col = $pdo->prepare("SELECT COUNT(*) FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='roles' AND column_name='landing_page'");
            $col->execute();
            if ((int)$col->fetchColumn() === 0) return '';

            $stmt = $pdo->prepare("SELECT landing_page FROM roles WHERE role_key=:k AND COALESCE(is_active,1)=1 LIMIT 1");
            $stmt->execute([':k' => $roleKey]);
            $val = (string)($stmt->fetchColumn() ?: '');
            // Only allow site-relative paths.
            if ($val !== '' && preg_match('#^/[A-Za-z0-9_\-/\.]*$#', $val) && strpos($val, '//') === false) {
                return $val;
            }
        } catch (Throwable $e) { /* fall through to default */ }
        return '';
    }
}

if (!rp_is_admin()) {
    http_response_code(403);
    require_once __DIR__ . '/../../includes/header.php';
    echo '<div class="alert alert-danger">Access denied. Only Admin / Owner can manage permissions.</div>';
    require_once __DIR__ . '/../../includes/footer.php';
    exit;
}

$errors = [];

try {
    $pdo->exec("CREATE TABLE IF NOT EXISTS roles (
        id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
        role_key VARCHAR(80) NOT NULL,
        role_name VARCHAR(120) NOT NULL,
        description TEXT NULL,
        is_system TINYINT(1) NOT NULL DEFAULT 0,
        is_active TINYINT(1) NOT NULL DEFAULT 1,
        created_at TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
        updated_at TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
        UNIQUE KEY uq_role_key (role_key)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");

    $pdo->exec("CREATE TABLE IF NOT EXISTS role_permissions (
        id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
        role_key VARCHAR(80) NOT NULL,
        permission_key VARCHAR(120) NOT NULL,
        can_view TINYINT(1) NOT NULL DEFAULT 0,
        can_create TINYINT(1) NOT NULL DEFAULT 0,
        can_edit TINYINT(1) NOT NULL DEFAULT 0,
        can_delete TINYINT(1) NOT NULL DEFAULT 0,
        can_approve TINYINT(1) NOT NULL DEFAULT 0,
        created_at TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
        updated_at TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
        UNIQUE KEY uq_role_permission (role_key, permission_key),
        INDEX idx_role_key (role_key),
        INDEX idx_permission_key (permission_key)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");

    $pdo->exec("CREATE TABLE IF NOT EXISTS permission_audit (
        id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
        role_key VARCHAR(80) NULL,
        permission_key VARCHAR(120) NULL,
        action VARCHAR(80) NOT NULL,
        details TEXT NULL,
        created_by INT UNSIGNED NULL,
        created_at TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
        INDEX idx_permission_audit_role (role_key),
        INDEX idx_permission_audit_created (created_at)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");

    $defaultRoles = [
        ['super_admin','Super Admin','Full system access',1],
        ['admin','Admin','System administrator',1],
        ['owner','Owner','Executive reporting and approvals',1],
        ['manager','Manager','Operational manager approvals and reports',1],
        ['frontdesk','Front Desk','Reservations, check-in/out and folios',1],
        ['cashier','Cashier','POS sales and shift handling',1],
        ['stores','Stores Clerk','Inventory and procurement control',1],
        ['accounts','Accounts','Payments, ledgers and reporting',1],
        ['housekeeping','Housekeeping','Room rack and housekeeping boards',1],
        ['user','User','Basic access',1],
    ];

    $stmt = $pdo->prepare("
        INSERT INTO roles (role_key, role_name, description, is_system)
        VALUES (:role_key, :role_name, :description, :is_system)
        ON DUPLICATE KEY UPDATE
            role_name=VALUES(role_name),
            description=VALUES(description),
            is_system=VALUES(is_system)
    ");
    foreach ($defaultRoles as $r) {
        $stmt->execute([
            ':role_key' => $r[0],
            ':role_name' => $r[1],
            ':description' => $r[2],
            ':is_system' => $r[3],
        ]);
    }

    /* Ensure roles has a landing_page column before seeding defaults into it. */
    try {
        $col = $pdo->query("SELECT COUNT(*) FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='roles' AND column_name='landing_page'")->fetchColumn();
        if ((int)$col === 0) {
            $pdo->exec("ALTER TABLE roles ADD COLUMN landing_page VARCHAR(255) NULL AFTER description");
        }
    } catch (Throwable $e) { /* reported below if it matters */ }

    /*
       Seed a sensible default landing page per built-in role, but ONLY where
       landing_page is still NULL - never overwrite an admin's choice. Waiters
       and cashiers land on the restaurant planner; front desk on Front Desk;
       stores on inventory; and so on.
    */
    $seedLanding = [
        'cashier'      => '/modules/restaurant/planner.php',
        'frontdesk'    => '/modules/frontdesk/index.php',
        'stores'       => '/modules/inventory/index.php',
        'housekeeping' => '/modules/frontdesk/housekeeping.php',
        'accounts'     => '/modules/reports/index.php',
        'manager'      => '/modules/dashboard/index.php',
        'owner'        => '/modules/dashboard/executive.php',
    ];
    try {
        $seedStmt = $pdo->prepare("UPDATE roles SET landing_page=:lp WHERE role_key=:rk AND landing_page IS NULL");
        foreach ($seedLanding as $rk => $lp) {
            $seedStmt->execute([':lp' => $lp, ':rk' => $rk]);
        }
    } catch (Throwable $e) { /* non-fatal seeding */ }
} catch (Throwable $e) {
    $errors[] = 'Could not prepare permissions tables: ' . $e->getMessage();
}

/*
   Landing-page options offered in the role editor. Each is a relative path
   (BASE_URL is prepended at login). Grouped for a readable dropdown. Admins
   can also type a custom path. Keep these aligned with real files in the app.
*/
$landingPageOptions = [
    'Overview' => [
        '/modules/dashboard/index.php'                      => 'Main Dashboard',
        '/modules/dashboard/executive.php'                  => 'Executive Dashboard',
    ],
    'Front Desk' => [
        '/modules/frontdesk/index.php'                      => 'Front Desk',
        '/modules/reservations/index.php'                   => 'Reservations',
        '/modules/frontdesk/arrivals.php'                   => 'Arrivals',
        '/modules/frontdesk/room_rack.php'                  => 'Room Rack',
    ],
    'Restaurant' => [
        '/modules/restaurant/planner.php'                   => 'Table Planner / POS',
        '/modules/restaurant/index.php'                     => 'Restaurant Dashboard',
        '/modules/restaurant/cashier.php'                   => 'Cashier / Close Tables',
        '/modules/restaurant/kitchen_display.php'           => 'Kitchen Display',
        '/modules/restaurant/bar_display.php'               => 'Bar Display',
        '/modules/restaurant/orders.php'                    => 'Restaurant Orders',
    ],
    'POS' => [
        '/modules/pos/pos.php'                              => 'POS Screen',
        '/modules/pos/orders.php'                           => 'POS Orders',
    ],
    'Stores & Inventory' => [
        '/modules/inventory/index.php'                      => 'Inventory Dashboard',
        '/modules/inventory/items.php'                      => 'Inventory Items',
        '/modules/inventory/internal_requisition.php'       => 'Internal Requisition',
        '/modules/inventory/stock_take.php'                 => 'Stock Take',
    ],
    'Housekeeping' => [
        '/modules/frontdesk/housekeeping.php'               => 'Housekeeping Board',
    ],
    'Finance & Management' => [
        '/modules/reports/index.php'                        => 'Reports',
        '/modules/finance/owner_profit.php'                 => 'Owner Profit Dashboard',
    ],
];

/* Flat lookup so we can label a stored path even if it's custom. */
$landingPageLabels = [];
foreach ($landingPageOptions as $grp => $opts) {
    foreach ($opts as $path => $label) $landingPageLabels[$path] = $label;
}

$permissionGroups = [
    'Overview' => [
        'dashboard' => 'Main Dashboard',
        'executive_dashboard' => 'Executive Dashboard',
    ],
    'Reservations & Front Desk' => [
        'reservations' => 'Reservations',
        'quotations' => 'Quotations',
        'quotation_create' => 'Create Quotation',
        'quotation_convert' => 'Convert Quotation to Booking',
        'availability_calendar' => 'Availability Calendar',
        'rooming' => 'Rooming / Planner',
        'guests' => 'Guests',
        'frontdesk' => 'Front Desk',
        'arrivals' => 'Arrivals',
        'departures' => 'Departures',
        'room_rack' => 'Room Rack',
        'housekeeping' => 'Housekeeping',
        'night_audit' => 'Night Audit',
        'folios' => 'Folios',
        'payments' => 'Guest Payments',
    ],
    'Stores & Inventory' => [
        'inventory_dashboard' => 'Inventory Dashboard',
        'inventory_items' => 'Inventory Items',
        'store_locations' => 'Store Locations',
        'suppliers' => 'Suppliers',
        'purchase_orders' => 'Purchase Orders',
        'internal_requisition' => 'Internal Requisition',
        'grn' => 'GRN / Purchases',
        'stock_movements' => 'Stock Movements',
        'stock_take' => 'Stock Take',
        'recipes' => 'Recipes',
        'recipe_profit_report' => 'Recipe Profit Report',
        'stock_valuation_report' => 'Stock Valuation',
        'low_stock_report' => 'Low Stock Report',
        'month_end_inventory' => 'Month-End Inventory Closing',
    ],
    'POS Controls' => [
        'pos' => 'POS Screen',
        'pos_orders' => 'POS Orders',
        'pos_void' => 'Void POS Receipts',
        'pos_shifts' => 'POS Shifts',
        'pos_approvals' => 'POS Approvals',
        'pos_sales_report' => 'POS Sales Report',
    ],
    'Restaurant' => [
        'restaurant_dashboard' => 'Restaurant Dashboard',
        'restaurant_planner' => 'Table Planner / POS',
        'restaurant_reservations' => 'Restaurant Reservations',
        'restaurant_reservation_calendar' => 'Reservation Calendar',
        'restaurant_orders' => 'Restaurant Orders',
        'restaurant_cashier' => 'Cashier / Close Tables',
        'restaurant_kitchen_display' => 'Kitchen Display',
        'restaurant_bar_display' => 'Bar Display',
        'restaurant_tables' => 'Tables Setup',
        'restaurant_menu' => 'Menu Setup',
        'restaurant_printers' => 'Printer Queue',
        'restaurant_reports' => 'Restaurant Reports',
    ],
    'Finance & Management' => [
        'supplier_ledger' => 'Supplier Ledger',
        'supplier_payments' => 'Supplier Payments',
        'owner_profit_dashboard' => 'Owner Profit Dashboard',
        'management_dashboard' => 'Management Dashboard',
        'audit_log' => 'Audit Log',
        'reports' => 'Reports',
    ],
    'Channel Manager' => [
        'channel_dashboard' => 'Channel Dashboard',
        'channel_settings' => 'Channel Connections',
        'channel_mapping' => 'Channel Mapping',
        'channel_push' => 'Push Availability/Rates',
        'channel_pull' => 'Pull Bookings',
        'channel_logs' => 'Channel Sync Logs',
    ],
    'System' => [
        'settings' => 'Settings',
        'role_permissions' => 'Role Permissions',
        'masters' => 'Masters',
    ],
];

$permissionLabels = [];
foreach ($permissionGroups as $group => $items) {
    foreach ($items as $key => $label) $permissionLabels[$key] = $label;
}

$defaultsByRole = [
    'super_admin' => ['*'],
    'admin' => ['*'],
    'owner' => ['dashboard','executive_dashboard','quotations','owner_profit_dashboard','management_dashboard','reports','pos_sales_report','recipe_profit_report','stock_valuation_report','low_stock_report','month_end_inventory','supplier_ledger','audit_log','restaurant_dashboard','restaurant_orders','restaurant_reports'],
    'manager' => ['dashboard','reservations','quotations','quotation_create','quotation_convert','availability_calendar','rooming','frontdesk','arrivals','departures','room_rack','housekeeping','night_audit','inventory_dashboard','internal_requisition','pos_orders','pos_shifts','pos_approvals','pos_sales_report','recipe_profit_report','low_stock_report','reports','audit_log','restaurant_dashboard','restaurant_planner','restaurant_reservations','restaurant_reservation_calendar','restaurant_orders','restaurant_cashier','restaurant_kitchen_display','restaurant_bar_display','restaurant_tables','restaurant_menu','restaurant_printers','restaurant_reports'],
    'frontdesk' => ['dashboard','reservations','quotations','quotation_create','quotation_convert','availability_calendar','rooming','guests','frontdesk','arrivals','departures','room_rack','folios','payments','restaurant_dashboard','restaurant_reservations','restaurant_reservation_calendar','restaurant_orders','restaurant_reports'],
    'cashier' => ['dashboard','pos','pos_orders','pos_shifts','restaurant_dashboard','restaurant_planner','restaurant_orders','restaurant_cashier','restaurant_kitchen_display','restaurant_bar_display'],
    'stores' => ['dashboard','inventory_dashboard','inventory_items','store_locations','suppliers','purchase_orders','internal_requisition','grn','stock_movements','stock_take','stock_valuation_report','low_stock_report'],
    'accounts' => ['dashboard','quotations','payments','supplier_ledger','supplier_payments','internal_requisition','pos_sales_report','stock_valuation_report','reports','audit_log','restaurant_orders','restaurant_reports'],
    'housekeeping' => ['dashboard','room_rack','housekeeping','arrivals','departures'],
    'user' => ['dashboard'],
];

if (($_SERVER['REQUEST_METHOD'] ?? 'GET') === 'POST') {
    try {
        if (function_exists('verify_csrf')) verify_csrf();

        $action = (string)($_POST['action'] ?? '');

        if ($action === 'save_permissions') {
            $roleKey = strtolower(trim((string)($_POST['role_key'] ?? '')));
            if ($roleKey === '') throw new RuntimeException('Role is required.');

            $stmt = $pdo->prepare("SELECT * FROM roles WHERE role_key=:role_key LIMIT 1");
            $stmt->execute([':role_key' => $roleKey]);
            $role = $stmt->fetch(PDO::FETCH_ASSOC);
            if (!$role) throw new RuntimeException('Role not found.');

            $posted = $_POST['perm'] ?? [];
            if (!is_array($posted)) $posted = [];

            $pdo->beginTransaction();

            $stmt = $pdo->prepare("DELETE FROM role_permissions WHERE role_key=:role_key");
            $stmt->execute([':role_key' => $roleKey]);

            $stmt = $pdo->prepare("
                INSERT INTO role_permissions
                (role_key, permission_key, can_view, can_create, can_edit, can_delete, can_approve)
                VALUES
                (:role_key, :permission_key, :can_view, :can_create, :can_edit, :can_delete, :can_approve)
            ");

            foreach ($permissionLabels as $permKey => $label) {
                $p = $posted[$permKey] ?? [];
                $stmt->execute([
                    ':role_key' => $roleKey,
                    ':permission_key' => $permKey,
                    ':can_view' => isset($p['view']) ? 1 : 0,
                    ':can_create' => isset($p['create']) ? 1 : 0,
                    ':can_edit' => isset($p['edit']) ? 1 : 0,
                    ':can_delete' => isset($p['delete']) ? 1 : 0,
                    ':can_approve' => isset($p['approve']) ? 1 : 0,
                ]);
            }

            $stmt = $pdo->prepare("
                INSERT INTO permission_audit
                (role_key, action, details, created_by)
                VALUES
                (:role_key, 'save_permissions', :details, :created_by)
            ");
            $stmt->execute([
                ':role_key' => $roleKey,
                ':details' => 'Permissions updated from role_permissions.php',
                ':created_by' => $_SESSION['user_id'] ?? null,
            ]);

            $pdo->commit();

            rp_flash('success', 'Permissions saved successfully for ' . $role['role_name'] . '.');
            header('Location: role_permissions.php?role=' . urlencode($roleKey));
            exit;
        }

        if ($action === 'apply_defaults') {
            $roleKey = strtolower(trim((string)($_POST['role_key'] ?? '')));
            if ($roleKey === '') throw new RuntimeException('Role is required.');
            if (!isset($defaultsByRole[$roleKey])) throw new RuntimeException('No defaults defined for this role.');

            $allowAll = in_array('*', $defaultsByRole[$roleKey], true);
            $allowed = $defaultsByRole[$roleKey];

            $pdo->beginTransaction();
            $stmt = $pdo->prepare("DELETE FROM role_permissions WHERE role_key=:role_key");
            $stmt->execute([':role_key' => $roleKey]);

            $stmt = $pdo->prepare("
                INSERT INTO role_permissions
                (role_key, permission_key, can_view, can_create, can_edit, can_delete, can_approve)
                VALUES
                (:role_key, :permission_key, :can_view, :can_create, :can_edit, :can_delete, :can_approve)
            ");

            foreach ($permissionLabels as $permKey => $label) {
                $enabled = $allowAll || in_array($permKey, $allowed, true);
                $canCreate = $enabled && !in_array($roleKey, ['owner','housekeeping','user'], true);
                $canEdit = $enabled && !in_array($roleKey, ['owner','housekeeping','user'], true);
                $canDelete = in_array($roleKey, ['super_admin','admin'], true);
                $canApprove = $enabled && in_array($roleKey, ['super_admin','admin','owner','manager'], true);

                $stmt->execute([
                    ':role_key' => $roleKey,
                    ':permission_key' => $permKey,
                    ':can_view' => $enabled ? 1 : 0,
                    ':can_create' => $canCreate ? 1 : 0,
                    ':can_edit' => $canEdit ? 1 : 0,
                    ':can_delete' => $canDelete ? 1 : 0,
                    ':can_approve' => $canApprove ? 1 : 0,
                ]);
            }

            $pdo->commit();

            rp_flash('success', 'Default permissions applied.');
            header('Location: role_permissions.php?role=' . urlencode($roleKey));
            exit;
        }

        if ($action === 'save_role') {
            $roleId = (int)($_POST['role_id'] ?? 0);
            $roleKey = strtolower(trim((string)($_POST['role_key'] ?? '')));
            $roleName = trim((string)($_POST['role_name'] ?? ''));
            $description = trim((string)($_POST['description'] ?? ''));
            $isActive = isset($_POST['is_active']) ? 1 : 0;

            /* Landing page: prefer the custom field when filled, else the dropdown. */
            $landingSelect = trim((string)($_POST['landing_page'] ?? ''));
            $landingCustom = trim((string)($_POST['landing_page_custom'] ?? ''));
            $landingPage = $landingCustom !== '' ? $landingCustom : $landingSelect;
            if ($landingPage !== '') {
                // Basic safety: must be a site-relative path, no scheme, no protocol-relative.
                if (!preg_match('#^/[A-Za-z0-9_\-/\.]*$#', $landingPage) || strpos($landingPage, '//') !== false) {
                    throw new RuntimeException('Landing page must be a site-relative path like /modules/restaurant/planner.php');
                }
            }

            if ($roleKey === '') throw new RuntimeException('Role key is required.');
            if (!preg_match('/^[a-z0-9_]+$/', $roleKey)) {
                throw new RuntimeException('Role key can only contain lowercase letters, numbers and underscore.');
            }
            if ($roleName === '') throw new RuntimeException('Role name is required.');

            if ($roleId > 0) {
                $stmt = $pdo->prepare("SELECT * FROM roles WHERE id=:id LIMIT 1");
                $stmt->execute([':id' => $roleId]);
                $existingRole = $stmt->fetch(PDO::FETCH_ASSOC);

                if (!$existingRole) {
                    throw new RuntimeException('Role not found for update.');
                }

                if (!empty($existingRole['is_system'])) {
                    $roleKey = (string)$existingRole['role_key'];
                } else {
                    $stmt = $pdo->prepare("
                        SELECT COUNT(*)
                        FROM roles
                        WHERE role_key=:role_key
                          AND id<>:id
                    ");
                    $stmt->execute([
                        ':role_key' => $roleKey,
                        ':id' => $roleId,
                    ]);

                    if ((int)$stmt->fetchColumn() > 0) {
                        throw new RuntimeException('Another role already uses this role key.');
                    }
                }

                $stmt = $pdo->prepare("
                    UPDATE roles
                    SET role_name=:role_name,
                        description=:description,
                        landing_page=:landing_page,
                        is_active=:is_active
                    WHERE id=:id
                ");
                $stmt->execute([
                    ':role_name' => $roleName,
                    ':description' => $description ?: null,
                    ':landing_page' => $landingPage !== '' ? $landingPage : null,
                    ':is_active' => $isActive,
                    ':id' => $roleId,
                ]);

                rp_flash('success', 'Role updated successfully.');
            } else {
                $stmt = $pdo->prepare("SELECT COUNT(*) FROM roles WHERE role_key=:role_key");
                $stmt->execute([':role_key' => $roleKey]);

                if ((int)$stmt->fetchColumn() > 0) {
                    throw new RuntimeException('Role key already exists. Please use a different role key.');
                }

                $stmt = $pdo->prepare("
                    INSERT INTO roles (role_key, role_name, description, landing_page, is_system, is_active)
                    VALUES (:role_key, :role_name, :description, :landing_page, 0, :is_active)
                ");
                $stmt->execute([
                    ':role_key' => $roleKey,
                    ':role_name' => $roleName,
                    ':description' => $description ?: null,
                    ':landing_page' => $landingPage !== '' ? $landingPage : null,
                    ':is_active' => $isActive,
                ]);

                $newRoleId = (int)$pdo->lastInsertId();
                if ($newRoleId <= 0) {
                    throw new RuntimeException('Role was not created. Please check the roles table.');
                }

                rp_flash('success', 'New role created successfully.');
            }

            $stmt = $pdo->prepare("
                INSERT INTO permission_audit
                (role_key, action, details, created_by)
                VALUES
                (:role_key, 'save_role', :details, :created_by)
            ");
            $stmt->execute([
                ':role_key' => $roleKey,
                ':details' => $roleId > 0 ? 'Role updated from role_permissions.php' : 'New role created from role_permissions.php',
                ':created_by' => $_SESSION['user_id'] ?? null,
            ]);

            header('Location: role_permissions.php?role=' . urlencode($roleKey));
            exit;
        }

    } catch (Throwable $e) {
        if ($pdo->inTransaction()) $pdo->rollBack();
        rp_flash('danger', $e->getMessage());
        header('Location: role_permissions.php');
        exit;
    }
}

$roles = [];
$isNewRoleMode = isset($_GET['new']) && (string)$_GET['new'] === '1';
$selectedRole = $isNewRoleMode ? '' : strtolower(trim((string)($_GET['role'] ?? rp_current_role())));
$rolePermissions = [];

try {
    $roles = $pdo->query("SELECT * FROM roles ORDER BY is_system DESC, role_name ASC")->fetchAll(PDO::FETCH_ASSOC);

    if (!$isNewRoleMode && !$selectedRole && $roles) {
        $selectedRole = (string)$roles[0]['role_key'];
    }

    if (!$isNewRoleMode && $selectedRole !== '') {
        $stmt = $pdo->prepare("SELECT * FROM role_permissions WHERE role_key=:role_key");
        $stmt->execute([':role_key' => $selectedRole]);
        foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
            $rolePermissions[$row['permission_key']] = $row;
        }
    }
} catch (Throwable $e) {
    $errors[] = 'Could not load permissions: ' . $e->getMessage();
}

$selectedRoleRow = null;
if (!$isNewRoleMode) {
    foreach ($roles as $role) {
        if ($role['role_key'] === $selectedRole) {
            $selectedRoleRow = $role;
            break;
        }
    }
}

$auditRows = [];
try {
    $stmt = $pdo->prepare("
        SELECT *
        FROM permission_audit
        WHERE (:role_key = '' OR role_key = :role_key)
        ORDER BY created_at DESC, id DESC
        LIMIT 50
    ");
    $stmt->execute([':role_key' => $selectedRole]);
    $auditRows = $stmt->fetchAll(PDO::FETCH_ASSOC);
} catch (Throwable $e) {}

$flashes = rp_get_flash();

require_once __DIR__ . '/../../includes/header.php';
?>

<div class="hero-band no-print">
    <div class="row g-4 align-items-center">
        <div class="col-lg-8">
            <div class="page-eyebrow text-white-50"><i class="bi bi-shield-lock"></i> System Security</div>
            <div class="hero-title mt-2">Role Permissions</div>
            <div class="hero-subtitle mt-2">
                Control access for cashiers, managers, stores, accounts, front desk, admin and owner users.
            </div>
        </div>
        <div class="col-lg-4 text-lg-end">
            <a href="<?php echo BASE_URL; ?>/modules/pos/pos_approvals.php" class="btn btn-light me-2">
                <i class="bi bi-shield-check me-2"></i>Approvals
            </a>
            <a href="<?php echo BASE_URL; ?>/modules/settings/lodge_settings.php" class="btn btn-outline-light">
                <i class="bi bi-sliders me-2"></i>Settings
            </a>
        </div>
    </div>
</div>

<?php foreach ($flashes as $flash): ?>
    <div class="alert alert-<?php echo h($flash['type']); ?>"><?php echo h($flash['message']); ?></div>
<?php endforeach; ?>

<?php if ($errors): ?>
    <div class="alert alert-danger">
        <div class="fw-bold mb-2">Please fix the following:</div>
        <ul class="mb-0"><?php foreach ($errors as $err): ?><li><?php echo h($err); ?></li><?php endforeach; ?></ul>
    </div>
<?php endif; ?>

<div class="row g-4">
    <div class="col-xl-3">
        <div class="card panel-card mb-4">
            <div class="card-header">
                <h5 class="mb-0">Roles</h5>
            </div>
            <div class="card-body p-0">
                <div class="role-list">
                    <?php foreach ($roles as $role): ?>
                        <a href="role_permissions.php?role=<?php echo urlencode($role['role_key']); ?>"
                           class="role-link <?php echo $selectedRole === $role['role_key'] ? 'active' : ''; ?>">
                            <div>
                                <strong><?php echo h($role['role_name']); ?></strong>
                                <div class="small text-muted"><?php echo h($role['role_key']); ?></div>
                            </div>
                            <?php if ((int)$role['is_active'] === 1): ?>
                                <span class="badge text-bg-success">Active</span>
                            <?php else: ?>
                                <span class="badge text-bg-secondary">Off</span>
                            <?php endif; ?>
                        </a>
                    <?php endforeach; ?>
                </div>
            </div>
        </div>

        <div class="card panel-card">
            <div class="card-header">
                <h5 class="mb-0"><?php echo $isNewRoleMode ? 'New Role' : 'Add / Edit Role'; ?></h5>
            </div>
            <div class="card-body">
                <a href="role_permissions.php?new=1" class="btn btn-outline-primary w-100 mb-3">
                    <i class="bi bi-plus-circle me-2"></i>New Role
                </a>

                <?php if ($isNewRoleMode): ?>
                    <div class="alert alert-info small">
                        Enter a new role key and name, then save. After saving, you can tick permissions for the new role.
                    </div>
                <?php endif; ?>

                <form method="post">
                    <?php if (function_exists('csrf_field')) echo csrf_field(); ?>
                    <input type="hidden" name="action" value="save_role">
                    <input type="hidden" name="role_id" value="<?php echo $isNewRoleMode ? 0 : (int)($selectedRoleRow['id'] ?? 0); ?>">

                    <div class="mb-3">
                        <label class="form-label">Role Key</label>
                        <input type="text"
                               name="role_key"
                               class="form-control"
                               value="<?php echo $isNewRoleMode ? '' : h($selectedRoleRow['role_key'] ?? ''); ?>"
                               <?php echo (!$isNewRoleMode && !empty($selectedRoleRow['is_system'])) ? 'readonly' : ''; ?>
                               placeholder="e.g. restaurant_manager"
                               required>
                        <div class="form-text">
                            Use lowercase letters, numbers and underscores only.
                        </div>
                    </div>

                    <div class="mb-3">
                        <label class="form-label">Role Name</label>
                        <input type="text"
                               name="role_name"
                               class="form-control"
                               value="<?php echo $isNewRoleMode ? '' : h($selectedRoleRow['role_name'] ?? ''); ?>"
                               required>
                    </div>

                    <div class="mb-3">
                        <label class="form-label">Description</label>
                        <textarea name="description" class="form-control" rows="3"><?php echo $isNewRoleMode ? '' : h($selectedRoleRow['description'] ?? ''); ?></textarea>
                    </div>

                    <?php $currentLanding = $isNewRoleMode ? '' : (string)($selectedRoleRow['landing_page'] ?? ''); ?>
                    <?php $isKnownLanding = $currentLanding === '' || isset($landingPageLabels[$currentLanding]); ?>
                    <div class="mb-3">
                        <label class="form-label">Default Landing Page</label>
                        <select name="landing_page" id="landing_page_select" class="form-select">
                            <option value="">— System default (dashboard) —</option>
                            <?php foreach ($landingPageOptions as $grp => $opts): ?>
                                <optgroup label="<?php echo h($grp); ?>">
                                    <?php foreach ($opts as $path => $label): ?>
                                        <option value="<?php echo h($path); ?>" <?php echo ($isKnownLanding && $currentLanding === $path) ? 'selected' : ''; ?>>
                                            <?php echo h($label); ?>
                                        </option>
                                    <?php endforeach; ?>
                                </optgroup>
                            <?php endforeach; ?>
                            <option value="__custom__" <?php echo (!$isKnownLanding) ? 'selected' : ''; ?>>Custom path…</option>
                        </select>
                        <div class="form-text">Where users with this role land right after logging in. E.g. waiters/cashiers → Table Planner.</div>
                    </div>

                    <div class="mb-3 <?php echo (!$isKnownLanding) ? '' : 'd-none'; ?>" id="landing_page_custom_wrap">
                        <label class="form-label">Custom Landing Path</label>
                        <input type="text" name="landing_page_custom" id="landing_page_custom"
                               class="form-control"
                               value="<?php echo (!$isKnownLanding) ? h($currentLanding) : ''; ?>"
                               placeholder="/modules/restaurant/planner.php">
                        <div class="form-text">Site-relative path starting with “/”. Overrides the dropdown when filled.</div>
                    </div>

                    <label class="setting-check mb-3">
                        <input type="checkbox" name="is_active" value="1" <?php echo $isNewRoleMode || (int)($selectedRoleRow['is_active'] ?? 1) === 1 ? 'checked' : ''; ?>>
                        <span>Active Role</span>
                    </label>

                    <button class="btn btn-primary w-100">
                        <i class="bi bi-save me-2"></i><?php echo $isNewRoleMode ? 'Create Role' : 'Save Role'; ?>
                    </button>
                </form>
            </div>
        </div>
    </div>

    <div class="col-xl-9">
        <div class="card panel-card mb-4">
            <div class="card-header d-flex justify-content-between align-items-center">
                <div>
                    <h5 class="mb-0">
                        Permissions:
                        <?php echo h($selectedRoleRow['role_name'] ?? $selectedRole); ?>
                    </h5>
                    <div class="small text-muted">
                        Tick what this role can do. View controls menu/page access; approve controls manager actions.
                    </div>
                </div>

                <?php if (!$isNewRoleMode && $selectedRoleRow): ?>
                    <form method="post" onsubmit="return confirm('Apply default permissions for this role?');">
                        <?php if (function_exists('csrf_field')) echo csrf_field(); ?>
                        <input type="hidden" name="action" value="apply_defaults">
                        <input type="hidden" name="role_key" value="<?php echo h($selectedRole); ?>">
                        <button class="btn btn-sm btn-outline-primary">
                            <i class="bi bi-magic me-1"></i>Apply Defaults
                        </button>
                    </form>
                <?php endif; ?>
            </div>

            <div class="card-body p-0">
                <?php if ($isNewRoleMode): ?>
                    <div class="p-4">
                        <div class="alert alert-warning mb-0">
                            Save the new role first. The permissions table will become available immediately after the role is created.
                        </div>
                    </div>
                <?php elseif (!$selectedRoleRow): ?>
                    <div class="p-4">
                        <div class="alert alert-danger mb-0">
                            Selected role was not found.
                        </div>
                    </div>
                <?php else: ?>
                <form method="post">
                    <?php if (function_exists('csrf_field')) echo csrf_field(); ?>
                    <input type="hidden" name="action" value="save_permissions">
                    <input type="hidden" name="role_key" value="<?php echo h($selectedRole); ?>">

                    <div class="table-responsive permission-grid-pane">
                        <table class="table table-modern align-middle mb-0 permission-table">
                            <thead>
                            <tr>
                                <th style="min-width:260px">Module / Permission</th>
                                <th class="text-center">View</th>
                                <th class="text-center">Create</th>
                                <th class="text-center">Edit</th>
                                <th class="text-center">Delete</th>
                                <th class="text-center">Approve</th>
                            </tr>
                            </thead>
                            <tbody>
                            <?php foreach ($permissionGroups as $group => $perms): ?>
                                <tr class="group-row">
                                    <td colspan="6"><?php echo h($group); ?></td>
                                </tr>
                                <?php foreach ($perms as $key => $label): ?>
                                    <?php $p = $rolePermissions[$key] ?? []; ?>
                                    <tr>
                                        <td>
                                            <strong><?php echo h($label); ?></strong>
                                            <div class="small text-muted"><?php echo h($key); ?></div>
                                        </td>
                                        <?php foreach (['view'=>'can_view','create'=>'can_create','edit'=>'can_edit','delete'=>'can_delete','approve'=>'can_approve'] as $short => $col): ?>
                                            <td class="text-center">
                                                <input class="form-check-input perm-check"
                                                       type="checkbox"
                                                       name="perm[<?php echo h($key); ?>][<?php echo h($short); ?>]"
                                                       value="1"
                                                       <?php echo !empty($p[$col]) ? 'checked' : ''; ?>>
                                            </td>
                                        <?php endforeach; ?>
                                    </tr>
                                <?php endforeach; ?>
                            <?php endforeach; ?>
                            </tbody>
                        </table>
                    </div>

                    <div class="p-3 border-top bg-light d-flex justify-content-between align-items-center">
                        <div class="text-muted small">
                            Helper functions for enforcement are shown below.
                        </div>
                        <button class="btn btn-success">
                            <i class="bi bi-shield-check me-2"></i>Save Permissions
                        </button>
                    </div>
                </form>
                <?php endif; ?>
            </div>
        </div>

        <div class="card panel-card mb-4" style="display:none">
            <div class="card-header">
                <h5 class="mb-0">How to Enforce in Any Page</h5>
            </div>
            <div class="card-body">
                <p class="mb-2">Add this helper file once, then protect pages like this:</p>

<pre class="code-box"><code>require_once __DIR__ . '/../../includes/permission_check.php';

require_permission($pdo, 'pos', 'view');          // open POS page
require_permission($pdo, 'pos_void', 'approve'); // void receipt
require_permission($pdo, 'stock_movements', 'create');</code></pre>

                <p class="mb-2 mt-3">Create this small helper file as:</p>
                <code>/rooms/includes/permission_check.php</code>

<pre class="code-box"><code>&lt;?php
if (!function_exists('current_role_key')) {
    function current_role_key(): string {
        if (function_exists('current_user_role')) return strtolower((string)current_user_role());
        return strtolower((string)($_SESSION['role'] ?? $_SESSION['user_role'] ?? $_SESSION['type'] ?? 'user'));
    }
}

if (!function_exists('has_permission')) {
    function has_permission(PDO $pdo, string $permissionKey, string $action = 'view'): bool {
        $role = current_role_key();

        if (in_array($role, ['super_admin','admin'], true)) {
            return true;
        }

        $columnMap = [
            'view' =&gt; 'can_view',
            'create' =&gt; 'can_create',
            'edit' =&gt; 'can_edit',
            'delete' =&gt; 'can_delete',
            'approve' =&gt; 'can_approve',
        ];

        $column = $columnMap[$action] ?? 'can_view';

        $stmt = $pdo-&gt;prepare("
            SELECT {$column}
            FROM role_permissions
            WHERE role_key = :role_key
              AND permission_key = :permission_key
            LIMIT 1
        ");
        $stmt-&gt;execute([
            ':role_key' =&gt; $role,
            ':permission_key' =&gt; $permissionKey,
        ]);

        return (int)$stmt-&gt;fetchColumn() === 1;
    }
}

if (!function_exists('require_permission')) {
    function require_permission(PDO $pdo, string $permissionKey, string $action = 'view'): void {
        if (!has_permission($pdo, $permissionKey, $action)) {
            http_response_code(403);
            die('&lt;div style="padding:20px;font-family:Arial"&gt;&lt;h3&gt;Access denied&lt;/h3&gt;&lt;p&gt;You do not have permission to access this page.&lt;/p&gt;&lt;/div&gt;');
        }
    }
}</code></pre>
            </div>
        </div>

        <div class="card panel-card">
            <div class="card-header">
                <h5 class="mb-0">Permission Audit</h5>
            </div>
            <div class="card-body p-0">
                <table class="table table-modern mb-0">
                    <thead>
                    <tr>
                        <th>Date</th>
                        <th>Role</th>
                        <th>Action</th>
                        <th>Details</th>
                    </tr>
                    </thead>
                    <tbody>
                    <?php if (!$auditRows): ?>
                        <tr><td colspan="4" class="text-center text-muted py-4">No audit records.</td></tr>
                    <?php else: foreach ($auditRows as $row): ?>
                        <tr>
                            <td><?php echo h($row['created_at']); ?></td>
                            <td><strong><?php echo h($row['role_key']); ?></strong></td>
                            <td><?php echo h($row['action']); ?></td>
                            <td><?php echo h($row['details']); ?></td>
                        </tr>
                    <?php endforeach; endif; ?>
                    </tbody>
                </table>
            </div>
        </div>
    </div>
</div>

<style>
.role-list{display:flex;flex-direction:column}
.role-link{display:flex;justify-content:space-between;align-items:center;gap:10px;padding:14px 16px;text-decoration:none;color:#0f172a;border-bottom:1px solid rgba(15,23,42,.08)}
.role-link:hover{background:#f8fafc}
.role-link.active{background:#eff6ff;color:#1d4ed8}
.setting-check{display:flex;align-items:center;gap:8px;border:1px solid rgba(15,23,42,.10);background:#fff;border-radius:14px;padding:10px 12px;font-weight:800;font-size:13px;color:#475569;cursor:pointer}
.setting-check input{width:16px;height:16px}
.permission-grid-pane{
    max-height:calc(100vh - 275px);
    min-height:420px;
    overflow:auto;
    position:relative;
    border-top:1px solid rgba(15,23,42,.08);
    border-bottom:1px solid rgba(15,23,42,.08);
    background:#fff;
}
.permission-table{
    border-collapse:separate;
    border-spacing:0;
}
.permission-table thead th{
    position:sticky;
    top:0;
    z-index:20;
    background:#f8fafc!important;
    color:#334155;
    border-bottom:1px solid #cbd5e1!important;
    box-shadow:0 2px 5px rgba(15,23,42,.08);
    font-size:12px;
    font-weight:900;
    letter-spacing:.025em;
    white-space:nowrap;
}
.permission-table thead th:first-child{
    left:0;
    z-index:22;
}
.permission-table tbody td:first-child{
    position:sticky;
    left:0;
    z-index:5;
    background:#fff;
    box-shadow:1px 0 0 rgba(15,23,42,.08);
}
.permission-table tbody tr:nth-child(even):not(.group-row) td:first-child{
    background:#fbfdff;
}
.permission-table tbody tr:hover:not(.group-row) td,
.permission-table tbody tr:hover:not(.group-row) td:first-child{
    background:#f1f5f9;
}
.permission-table .group-row td{
    position:sticky;
    top:42px;
    z-index:12;
    background:#0f172a!important;
    color:#fff!important;
    font-weight:900;
    text-transform:uppercase;
    font-size:12px;
    letter-spacing:.06em;
}
.permission-table .group-row td:first-child{
    left:0;
    z-index:13;
    box-shadow:none;
}
.perm-check{width:18px;height:18px}
.code-box{background:#0f172a;color:#e2e8f0;border-radius:18px;padding:16px;overflow:auto;font-size:12px}
@media (max-width:991.98px){
    .permission-grid-pane{max-height:70vh;min-height:360px}
}
</style>

<script>
(function () {
    var sel = document.getElementById('landing_page_select');
    var wrap = document.getElementById('landing_page_custom_wrap');
    var input = document.getElementById('landing_page_custom');
    if (!sel || !wrap) return;

    function sync() {
        var custom = sel.value === '__custom__';
        wrap.classList.toggle('d-none', !custom);
        // When a real dropdown path is chosen, clear the custom box so it
        // doesn't override the selection on submit.
        if (!custom && input) input.value = '';
        // The value "__custom__" is only a UI marker - blank it out on submit
        // so the server sees an empty select and uses the custom field instead.
        if (custom) sel.setAttribute('data-marker', '1'); else sel.removeAttribute('data-marker');
    }

    sel.addEventListener('change', sync);

    // Before submit, if "Custom path…" is selected, null the select value so
    // only landing_page_custom is sent.
    var form = sel.closest('form');
    if (form) {
        form.addEventListener('submit', function () {
            if (sel.value === '__custom__') sel.value = '';
        });
    }

    sync();
})();
</script>

<?php require_once __DIR__ . '/../../includes/footer.php'; ?>
