<?php

if (!defined('ABSPATH')) {
    exit;
}

final class SPP_Admin_Page
{
    public function __construct(
        private SPP_Repository $repository,
        private SPP_Permissions $permissions,
        private SPP_Proxmox_Client $proxmox
    ) {
    }

    public function register_hooks(): void
    {
        add_action('admin_menu', [$this, 'register_menu']);
        add_action('admin_enqueue_scripts', [$this, 'enqueue_assets']);
        add_action('admin_post_spp_save_settings', [$this, 'save_settings']);
        add_action('admin_post_spp_save_user_access', [$this, 'save_user_access']);
        add_action('admin_post_spp_save_template', [$this, 'save_template']);
    }

    public function register_menu(): void
    {
        add_menu_page(
            'Support Provisioning',
            'Support Provisioning',
            'exist',
            'support-provisioning-portal',
            [$this, 'render'],
            'dashicons-cloud',
            58
        );
    }

    public function enqueue_assets(string $hook): void
    {
        if ($hook !== 'toplevel_page_support-provisioning-portal') {
            return;
        }

        wp_enqueue_style('spp-portal', SPP_PLUGIN_URL . 'assets/portal.css', [], SPP_VERSION);
        wp_enqueue_script('spp-portal', SPP_PLUGIN_URL . 'assets/portal.js', [], SPP_VERSION, true);
    }

    public function render(): void
    {
        if (!$this->permissions->current_user_has_any()) {
            wp_die(esc_html__('You do not have permission to access this page.', 'support-provisioning-portal'));
        }

        $can_view_portal = $this->permissions->current_user_has(SPP_Permissions::VIEW_PORTAL);
        $can_manage_templates = $this->permissions->current_user_has(SPP_Permissions::MANAGE_TEMPLATES);
        $can_manage_settings = $this->permissions->current_user_has(SPP_Permissions::MANAGE_SETTINGS);
        $can_manage_permissions = $this->permissions->current_user_has(SPP_Permissions::MANAGE_PERMISSIONS);
        ?>
        <div class="wrap spp-admin-wrap">
            <h1><?php echo esc_html__('Support Provisioning Portal', 'support-provisioning-portal'); ?></h1>
            <?php $this->render_notices(); ?>
            <div class="<?php echo esc_attr($can_view_portal && $can_manage_settings ? 'spp-admin-grid' : 'spp-admin-stack'); ?>">
                <div>
                    <?php
                    if ($can_view_portal) {
                        $this->render_app_root();
                    } else {
                        $this->render_admin_only_notice();
                    }
                    ?>
                </div>
                <?php if ($can_manage_settings) : ?>
                    <div class="spp-admin-side">
                        <?php $this->render_settings(); ?>
                    </div>
                <?php endif; ?>
            </div>
            <?php
            if ($can_manage_templates) {
                $this->render_template_management();
            }

            if ($can_manage_permissions) {
                $this->render_user_access_management();
            }
            ?>
        </div>
        <?php
    }

    private function render_notices(): void
    {
        $notice = isset($_GET['spp_notice']) ? sanitize_key((string) wp_unslash($_GET['spp_notice'])) : '';

        if ($notice === '') {
            return;
        }

        $messages = [
            'settings_saved' => __('Settings saved.', 'support-provisioning-portal'),
            'template_saved' => __('Template saved.', 'support-provisioning-portal'),
            'template_removed' => __('Template removed from new provisioning.', 'support-provisioning-portal'),
            'template_error' => __('Template could not be saved. Check the fields and confirm the selected Proxmox VM or LXC template exists on the configured node.', 'support-provisioning-portal'),
            'user_access_saved' => __('User rights saved.', 'support-provisioning-portal'),
            'manager_required' => __('At least one user must keep the Manage user rights permission.', 'support-provisioning-portal'),
        ];

        if (!isset($messages[$notice])) {
            return;
        }

        $class = in_array($notice, ['manager_required', 'template_error'], true) ? 'notice notice-error' : 'notice notice-success';
        printf(
            '<div class="%s"><p>%s</p></div>',
            esc_attr($class),
            esc_html($messages[$notice])
        );
    }

    private function render_admin_only_notice(): void
    {
        ?>
        <div class="spp-panel spp-admin-notice">
            <p><?php echo esc_html__('Portal access is not enabled for your user. Administrative sections available to you are shown on this page.', 'support-provisioning-portal'); ?></p>
        </div>
        <?php
    }

    private function render_app_root(): void
    {
        ?>
        <div
            id="spp-portal-root"
            class="spp-portal"
            data-rest-url="<?php echo esc_url_raw(rest_url('support-provisioning/v1')); ?>"
            data-nonce="<?php echo esc_attr(wp_create_nonce('wp_rest')); ?>"
            data-permissions="<?php echo esc_attr((string) wp_json_encode($this->permissions->current_user_permissions())); ?>"
        ></div>
        <?php
    }

    private function render_settings(): void
    {
        ?>
        <form class="spp-settings" method="post" action="<?php echo esc_url(admin_url('admin-post.php')); ?>">
            <input type="hidden" name="action" value="spp_save_settings">
            <?php wp_nonce_field('spp_save_settings'); ?>
            <h2><?php echo esc_html__('Proxmox Settings', 'support-provisioning-portal'); ?></h2>
            <label>
                <span>Mode</span>
                <select name="spp_proxmox_mode">
                    <option value="mock" <?php selected(get_option('spp_proxmox_mode', 'mock'), 'mock'); ?>>Mock</option>
                    <option value="http" <?php selected(get_option('spp_proxmox_mode', 'mock'), 'http'); ?>>HTTP token auth</option>
                </select>
            </label>
            <label>
                <span>Base URL</span>
                <input name="spp_proxmox_base_url" type="url" value="<?php echo esc_attr(get_option('spp_proxmox_base_url', '')); ?>" placeholder="https://proxmox.example.internal:8006">
            </label>
            <label>
                <span>Token ID</span>
                <input name="spp_proxmox_token_id" type="text" value="<?php echo esc_attr(get_option('spp_proxmox_token_id', '')); ?>" placeholder="user@realm!token-name">
            </label>
            <label>
                <span>Token Secret</span>
                <input name="spp_proxmox_token_secret" type="password" value="" placeholder="Leave blank to keep existing secret">
            </label>
            <label>
                <span>Node</span>
                <input name="spp_proxmox_node" type="text" value="<?php echo esc_attr(get_option('spp_proxmox_node', 'pve-01')); ?>">
            </label>
            <label>
                <span>LXC rootfs storage</span>
                <input name="spp_lxc_rootfs_storage" type="text" value="<?php echo esc_attr(get_option('spp_lxc_rootfs_storage', '')); ?>" placeholder="local-lvm">
            </label>
            <label>
                <span>LXC network bridge</span>
                <input name="spp_lxc_bridge" type="text" value="<?php echo esc_attr(get_option('spp_lxc_bridge', 'vmbr0')); ?>" placeholder="vmbr0">
            </label>
            <h2><?php echo esc_html__('RAM Contingents', 'support-provisioning-portal'); ?></h2>
            <p class="description"><?php echo esc_html__('Set 0 for unlimited. Active allocations include provisioning, stopped, running, and deleting deployments.', 'support-provisioning-portal'); ?></p>
            <label>
                <span>Default per-user RAM limit (MB)</span>
                <input name="spp_quota_user_memory_mb" type="number" min="0" step="256" value="<?php echo esc_attr((string) get_option('spp_quota_user_memory_mb', 0)); ?>">
            </label>
            <label>
                <span>Global RAM limit (MB)</span>
                <input name="spp_quota_global_memory_mb" type="number" min="0" step="256" value="<?php echo esc_attr((string) get_option('spp_quota_global_memory_mb', 0)); ?>">
            </label>
            <?php submit_button('Save Settings'); ?>
        </form>
        <?php
    }

    private function render_template_management(): void
    {
        $approved_templates = $this->repository->admin_templates();
        $active_template_keys = $this->repository->active_template_identity_keys();
        $proxmox_error = null;

        try {
            $proxmox_templates = $this->proxmox->list_templates();
        } catch (Throwable $error) {
            $proxmox_templates = [];
            $proxmox_error = $error->getMessage();
        }
        ?>
        <section class="spp-settings spp-template-admin">
            <div class="spp-section-header">
                <div>
                    <h2><?php echo esc_html__('Templates', 'support-provisioning-portal'); ?></h2>
                    <p class="description"><?php echo esc_html__('Approved templates are stored by the plugin and used for new deployments. Proxmox templates can be imported from the configured node.', 'support-provisioning-portal'); ?></p>
                </div>
            </div>

            <h3><?php echo esc_html__('Approved Templates', 'support-provisioning-portal'); ?></h3>
            <div class="spp-template-list">
                <?php if (empty($approved_templates)) : ?>
                    <div class="spp-panel spp-admin-notice">
                        <p><?php echo esc_html__('No plugin templates are approved yet. Import one from Proxmox below.', 'support-provisioning-portal'); ?></p>
                    </div>
                <?php endif; ?>
                <?php foreach ($approved_templates as $template) : ?>
                    <form class="spp-template-row" method="post" action="<?php echo esc_url(admin_url('admin-post.php')); ?>">
                        <input type="hidden" name="action" value="spp_save_template">
                        <input type="hidden" name="spp_template_id" value="<?php echo esc_attr((string) $template['id']); ?>">
                        <?php wp_nonce_field('spp_save_template'); ?>
                        <div class="spp-template-row-head">
                            <div>
                                <strong><?php echo esc_html((string) $template['name']); ?></strong>
                                <span><?php echo esc_html($this->template_identity_label($template)); ?></span>
                            </div>
                            <?php if (!empty($template['isActive'])) : ?>
                                <span class="spp-badge RUNNING"><?php echo esc_html__('Active', 'support-provisioning-portal'); ?></span>
                            <?php else : ?>
                                <span class="spp-badge STOPPED"><?php echo esc_html__('Inactive', 'support-provisioning-portal'); ?></span>
                            <?php endif; ?>
                        </div>
                        <div class="spp-template-fields">
                            <input type="hidden" name="spp_provisioning_type" value="<?php echo esc_attr((string) $template['provisioningType']); ?>">
                            <label>Name
                                <input name="spp_template_name" type="text" required maxlength="160" value="<?php echo esc_attr((string) $template['name']); ?>">
                            </label>
                            <label>Type
                                <input type="text" readonly value="<?php echo esc_attr($this->template_type_label((string) $template['provisioningType'])); ?>">
                            </label>
                            <?php if ((string) $template['provisioningType'] === 'lxc') : ?>
                                <input type="hidden" name="spp_proxmox_template_id" value="0">
                                <label>LXC template ref
                                    <input name="spp_proxmox_template_ref" type="text" readonly required value="<?php echo esc_attr((string) $template['proxmoxTemplateRef']); ?>">
                                </label>
                            <?php else : ?>
                                <input type="hidden" name="spp_proxmox_template_ref" value="">
                                <label>PVE template VMID
                                    <input name="spp_proxmox_template_id" type="number" min="1" required value="<?php echo esc_attr((string) $template['proxmoxTemplateId']); ?>">
                                </label>
                            <?php endif; ?>
                            <label>OS type
                                <?php $this->render_os_type_select((string) $template['osType']); ?>
                            </label>
                            <label>CPU cores
                                <input name="spp_cpu_cores" type="number" min="1" required value="<?php echo esc_attr((string) $template['cpuCores']); ?>">
                            </label>
                            <label>Memory MB
                                <input name="spp_memory_mb" type="number" min="128" step="128" required value="<?php echo esc_attr((string) $template['memoryMb']); ?>">
                            </label>
                            <label>Disk GB
                                <input name="spp_disk_gb" type="number" min="1" required value="<?php echo esc_attr((string) $template['diskGb']); ?>">
                            </label>
                            <label>Default TTL hours
                                <input name="spp_default_ttl_hours" type="number" min="1" max="720" required value="<?php echo esc_attr((string) $template['defaultTtlHours']); ?>">
                            </label>
                            <label class="spp-check">
                                <input name="spp_is_active" type="checkbox" value="1" <?php checked(!empty($template['isActive'])); ?>>
                                <span>Active for new deployments</span>
                            </label>
                            <label class="spp-template-description">Description
                                <textarea name="spp_template_description" rows="2" required><?php echo esc_textarea((string) $template['description']); ?></textarea>
                            </label>
                        </div>
                        <div class="spp-template-actions">
                            <button class="button button-primary" name="spp_template_action" value="save" type="submit"><?php echo esc_html__('Save Template', 'support-provisioning-portal'); ?></button>
                            <button class="button" name="spp_template_action" value="remove" type="submit"><?php echo esc_html__('Remove', 'support-provisioning-portal'); ?></button>
                        </div>
                    </form>
                <?php endforeach; ?>
            </div>

            <h3><?php echo esc_html__('Proxmox Templates On Configured Node', 'support-provisioning-portal'); ?></h3>
            <?php if ($proxmox_error !== null) : ?>
                <p class="spp-error"><?php echo esc_html($proxmox_error); ?></p>
            <?php elseif (empty($proxmox_templates)) : ?>
                <div class="spp-panel spp-admin-notice">
                    <p><?php echo esc_html__('No QEMU VM or LXC templates were returned by Proxmox for the configured node.', 'support-provisioning-portal'); ?></p>
                </div>
            <?php else : ?>
                <div class="spp-pve-template-grid">
                    <?php foreach ($proxmox_templates as $template) : ?>
                        <?php
                        $provisioning_type = $this->normalise_template_type((string) ($template['provisioningType'] ?? 'qemu'));
                        $template_ref = (string) ($template['templateRef'] ?? '');
                        $is_imported = in_array(
                            $this->template_identity_key($provisioning_type, (int) ($template['vmId'] ?? 0), $template_ref),
                            $active_template_keys,
                            true
                        );
                        ?>
                        <form class="spp-pve-template" method="post" action="<?php echo esc_url(admin_url('admin-post.php')); ?>">
                            <input type="hidden" name="action" value="spp_save_template">
                            <input type="hidden" name="spp_template_action" value="import">
                            <input type="hidden" name="spp_provisioning_type" value="<?php echo esc_attr($provisioning_type); ?>">
                            <input type="hidden" name="spp_template_name" value="<?php echo esc_attr((string) $template['name']); ?>">
                            <input type="hidden" name="spp_proxmox_template_id" value="<?php echo esc_attr((string) ($template['vmId'] ?? 0)); ?>">
                            <input type="hidden" name="spp_proxmox_template_ref" value="<?php echo esc_attr($template_ref); ?>">
                            <input type="hidden" name="spp_cpu_cores" value="<?php echo esc_attr((string) $template['cpuCores']); ?>">
                            <input type="hidden" name="spp_memory_mb" value="<?php echo esc_attr((string) $template['memoryMb']); ?>">
                            <input type="hidden" name="spp_disk_gb" value="<?php echo esc_attr((string) $template['diskGb']); ?>">
                            <?php wp_nonce_field('spp_save_template'); ?>
                            <div class="spp-template-row-head">
                                <div>
                                    <strong><?php echo esc_html((string) $template['name']); ?></strong>
                                    <span><?php echo esc_html($this->template_identity_label([
                                        'provisioningType' => $provisioning_type,
                                        'proxmoxTemplateId' => (int) ($template['vmId'] ?? 0),
                                        'proxmoxTemplateRef' => $template_ref,
                                    ])); ?></span>
                                </div>
                                <?php if ($is_imported) : ?>
                                    <span class="spp-badge RUNNING"><?php echo esc_html__('Imported', 'support-provisioning-portal'); ?></span>
                                <?php endif; ?>
                            </div>
                            <div class="spp-meta">
                                <span>Type<strong><?php echo esc_html($this->template_type_label($provisioning_type)); ?></strong></span>
                                <span>CPU<strong><?php echo esc_html((string) $template['cpuCores']); ?> cores</strong></span>
                                <span>Memory<strong><?php echo esc_html((string) $template['memoryMb']); ?> MB</strong></span>
                                <span>Disk<strong><?php echo esc_html((string) $template['diskGb']); ?> GB</strong></span>
                                <span>Status<strong><?php echo esc_html((string) $template['status']); ?></strong></span>
                            </div>
                            <?php if (!$is_imported) : ?>
                                <label>OS type
                                    <?php $this->render_os_type_select('LINUX'); ?>
                                </label>
                                <label>Default TTL hours
                                    <input name="spp_default_ttl_hours" type="number" min="1" max="720" value="168" required>
                                </label>
                                <label>Description
                                    <textarea name="spp_template_description" rows="2" required><?php echo esc_textarea($provisioning_type === 'lxc' ? sprintf('Imported from Proxmox LXC template %s.', $template_ref) : sprintf('Imported from Proxmox template VMID %d.', (int) $template['vmId'])); ?></textarea>
                                </label>
                                <button class="button button-primary" type="submit"><?php echo esc_html__('Import Template', 'support-provisioning-portal'); ?></button>
                            <?php endif; ?>
                        </form>
                    <?php endforeach; ?>
                </div>
            <?php endif; ?>

            <h3><?php echo esc_html__('Add QEMU Template Manually', 'support-provisioning-portal'); ?></h3>
            <form class="spp-template-row" method="post" action="<?php echo esc_url(admin_url('admin-post.php')); ?>">
                <input type="hidden" name="action" value="spp_save_template">
                <input type="hidden" name="spp_template_action" value="import">
                <input type="hidden" name="spp_provisioning_type" value="qemu">
                <input type="hidden" name="spp_proxmox_template_ref" value="">
                <?php wp_nonce_field('spp_save_template'); ?>
                <div class="spp-template-fields">
                    <label>Name
                        <input name="spp_template_name" type="text" required maxlength="160">
                    </label>
                    <label>PVE template VMID
                        <input name="spp_proxmox_template_id" type="number" min="1" required>
                    </label>
                    <label>OS type
                        <?php $this->render_os_type_select('LINUX'); ?>
                    </label>
                    <label>CPU cores
                        <input name="spp_cpu_cores" type="number" min="1" value="2" required>
                    </label>
                    <label>Memory MB
                        <input name="spp_memory_mb" type="number" min="128" step="128" value="2048" required>
                    </label>
                    <label>Disk GB
                        <input name="spp_disk_gb" type="number" min="1" value="32" required>
                    </label>
                    <label>Default TTL hours
                        <input name="spp_default_ttl_hours" type="number" min="1" max="720" value="168" required>
                    </label>
                    <label class="spp-template-description">Description
                        <textarea name="spp_template_description" rows="2" required></textarea>
                    </label>
                </div>
                <div class="spp-template-actions">
                    <button class="button button-primary" type="submit"><?php echo esc_html__('Add Template', 'support-provisioning-portal'); ?></button>
                </div>
            </form>
        </section>
        <?php
    }

    private function render_user_access_management(): void
    {
        $search = isset($_GET['spp_user_search']) ? sanitize_text_field((string) wp_unslash($_GET['spp_user_search'])) : '';
        $users = $this->users_for_access_table($search);
        $definitions = SPP_Permissions::definitions();
        ?>
        <section class="spp-settings spp-user-access">
            <div class="spp-section-header">
                <div>
                    <h2><?php echo esc_html__('User Rights', 'support-provisioning-portal'); ?></h2>
                    <p class="description"><?php echo esc_html__('SSO users appear here after their first WordPress sign-in.', 'support-provisioning-portal'); ?></p>
                </div>
                <form class="spp-user-search" method="get">
                    <input type="hidden" name="page" value="support-provisioning-portal">
                    <input name="spp_user_search" type="search" value="<?php echo esc_attr($search); ?>" placeholder="Search users">
                    <button class="button" type="submit"><?php echo esc_html__('Search', 'support-provisioning-portal'); ?></button>
                </form>
            </div>
            <?php if (empty($this->permissions->user_ids_with_permission(SPP_Permissions::MANAGE_PERMISSIONS))) : ?>
                <p class="spp-warning"><?php echo esc_html__('Assign Manage user rights to at least one user to finish permission bootstrap.', 'support-provisioning-portal'); ?></p>
            <?php endif; ?>
            <form method="post" action="<?php echo esc_url(admin_url('admin-post.php')); ?>">
                <input type="hidden" name="action" value="spp_save_user_access">
                <?php wp_nonce_field('spp_save_user_access'); ?>
                <table class="widefat striped spp-user-access-table">
                    <thead>
                        <tr>
                            <th><?php echo esc_html__('User', 'support-provisioning-portal'); ?></th>
                            <th><?php echo esc_html__('RAM override', 'support-provisioning-portal'); ?></th>
                            <th><?php echo esc_html__('Rights', 'support-provisioning-portal'); ?></th>
                        </tr>
                    </thead>
                    <tbody>
                        <?php if (empty($users)) : ?>
                            <tr>
                                <td colspan="3"><?php echo esc_html__('No users found.', 'support-provisioning-portal'); ?></td>
                            </tr>
                        <?php endif; ?>
                        <?php foreach ($users as $user) : ?>
                            <?php
                            $user_permissions = $this->permissions->for_user((int) $user->ID);
                            $quota = get_user_meta((int) $user->ID, 'spp_memory_quota_mb', true);
                            ?>
                            <tr>
                                <td>
                                    <input type="hidden" name="spp_user_ids[]" value="<?php echo esc_attr((string) $user->ID); ?>">
                                    <strong><?php echo esc_html($user->display_name !== '' ? $user->display_name : $user->user_login); ?></strong>
                                    <span class="spp-user-login"><?php echo esc_html($user->user_login); ?></span>
                                    <span class="spp-user-login"><?php echo esc_html($user->user_email); ?></span>
                                </td>
                                <td>
                                    <input
                                        class="small-text"
                                        name="spp_memory_quota_mb[<?php echo esc_attr((string) $user->ID); ?>]"
                                        type="number"
                                        min="0"
                                        step="256"
                                        value="<?php echo esc_attr((string) $quota); ?>"
                                        placeholder="Default"
                                    >
                                </td>
                                <td>
                                    <div class="spp-permission-groups">
                                        <?php foreach (SPP_Permissions::groups() as $group => $permissions) : ?>
                                            <fieldset>
                                                <legend><?php echo esc_html($group); ?></legend>
                                                <?php foreach ($permissions as $permission) : ?>
                                                    <label>
                                                        <input
                                                            type="checkbox"
                                                            name="spp_permissions[<?php echo esc_attr((string) $user->ID); ?>][]"
                                                            value="<?php echo esc_attr($permission); ?>"
                                                            <?php checked(in_array($permission, $user_permissions, true)); ?>
                                                        >
                                                        <span><?php echo esc_html($definitions[$permission]); ?></span>
                                                    </label>
                                                <?php endforeach; ?>
                                            </fieldset>
                                        <?php endforeach; ?>
                                    </div>
                                </td>
                            </tr>
                        <?php endforeach; ?>
                    </tbody>
                </table>
                <?php submit_button('Save User Rights'); ?>
            </form>
        </section>
        <?php
    }

    public function save_settings(): void
    {
        if (!$this->permissions->current_user_has(SPP_Permissions::MANAGE_SETTINGS)) {
            wp_die(esc_html__('You do not have permission to save these settings.', 'support-provisioning-portal'));
        }

        check_admin_referer('spp_save_settings');

        update_option('spp_proxmox_mode', $this->posted_string('spp_proxmox_mode') === 'http' ? 'http' : 'mock');
        update_option('spp_proxmox_base_url', $this->sanitize_proxmox_base_url($this->posted_string('spp_proxmox_base_url')));
        update_option('spp_proxmox_token_id', sanitize_text_field($this->posted_string('spp_proxmox_token_id')));
        $token_secret = sanitize_text_field($this->posted_string('spp_proxmox_token_secret'));
        if ($token_secret !== '') {
            update_option('spp_proxmox_token_secret', $token_secret);
        }
        update_option('spp_proxmox_node', sanitize_text_field($this->posted_string('spp_proxmox_node')));
        update_option('spp_lxc_rootfs_storage', $this->sanitize_proxmox_identifier($this->posted_string('spp_lxc_rootfs_storage')));
        update_option('spp_lxc_bridge', $this->sanitize_proxmox_identifier($this->posted_string('spp_lxc_bridge')));
        update_option('spp_quota_user_memory_mb', max(0, absint($this->posted_string('spp_quota_user_memory_mb'))));
        update_option('spp_quota_global_memory_mb', max(0, absint($this->posted_string('spp_quota_global_memory_mb'))));

        $this->redirect_to_admin_page('settings_saved');
    }

    public function save_template(): void
    {
        if (!$this->permissions->current_user_has(SPP_Permissions::MANAGE_TEMPLATES)) {
            wp_die(esc_html__('You do not have permission to save templates.', 'support-provisioning-portal'));
        }

        check_admin_referer('spp_save_template');

        $template_id = absint($this->posted_string('spp_template_id'));
        $action = sanitize_key($this->posted_string('spp_template_action'));

        if ($action === 'remove') {
            if ($template_id < 1) {
                $this->redirect_to_admin_page('template_error');
            }

            $this->repository->deactivate_template($template_id, get_current_user_id());
            $this->redirect_to_admin_page('template_removed');
        }

        $data = $this->posted_template_data();
        if ($data === null) {
            $this->redirect_to_admin_page('template_error');
        }

        if (!$this->proxmox_template_exists(
            (string) $data['provisioning_type'],
            (int) $data['proxmox_template_id'],
            (string) $data['proxmox_template_ref']
        )) {
            $this->redirect_to_admin_page('template_error');
        }

        if ($template_id > 0) {
            $this->repository->update_template($template_id, $data, get_current_user_id());
        } else {
            $this->repository->upsert_template($data, get_current_user_id());
        }

        $this->redirect_to_admin_page('template_saved');
    }

    public function save_user_access(): void
    {
        if (!$this->permissions->current_user_has(SPP_Permissions::MANAGE_PERMISSIONS)) {
            wp_die(esc_html__('You do not have permission to save user rights.', 'support-provisioning-portal'));
        }

        check_admin_referer('spp_save_user_access');

        $user_ids = $this->posted_user_ids();
        $posted_permissions = isset($_POST['spp_permissions']) ? (array) wp_unslash($_POST['spp_permissions']) : [];
        $posted_quotas = isset($_POST['spp_memory_quota_mb']) ? (array) wp_unslash($_POST['spp_memory_quota_mb']) : [];

        if (!$this->save_keeps_permission_manager($user_ids, $posted_permissions)) {
            $this->redirect_to_admin_page('manager_required');
        }

        foreach ($user_ids as $user_id) {
            $permissions = isset($posted_permissions[$user_id]) && is_array($posted_permissions[$user_id])
                ? SPP_Permissions::sanitize_permissions($posted_permissions[$user_id])
                : [];

            $quota_raw = isset($posted_quotas[$user_id]) ? sanitize_text_field((string) $posted_quotas[$user_id]) : '';
            $memory_quota_mb = $quota_raw === '' ? null : max(0, absint($quota_raw));

            $this->repository->update_user_access($user_id, $permissions, $memory_quota_mb, get_current_user_id());
        }

        $this->redirect_to_admin_page('user_access_saved');
    }

    /**
     * @return array<int, WP_User>
     */
    private function users_for_access_table(string $search): array
    {
        $args = [
            'fields' => 'all',
            'orderby' => 'display_name',
            'order' => 'ASC',
            'number' => 200,
        ];

        if ($search !== '') {
            $args['search'] = '*' . $search . '*';
            $args['search_columns'] = ['user_login', 'user_email', 'user_nicename', 'display_name'];
        }

        $users = get_users($args);

        return is_array($users) ? $users : [];
    }

    private function render_os_type_select(string $selected): void
    {
        $options = [
            'LINUX' => 'Linux',
            'WINDOWS' => 'Windows',
            'APPLIANCE' => 'Appliance',
            'OTHER' => 'Other',
        ];
        ?>
        <select name="spp_os_type">
            <?php foreach ($options as $value => $label) : ?>
                <option value="<?php echo esc_attr($value); ?>" <?php selected($selected, $value); ?>><?php echo esc_html($label); ?></option>
            <?php endforeach; ?>
        </select>
        <?php
    }

    private function posted_string(string $key): string
    {
        if (!isset($_POST[$key])) {
            return '';
        }

        $value = wp_unslash($_POST[$key]);

        return is_scalar($value) ? (string) $value : '';
    }

    private function sanitize_proxmox_base_url(string $value): string
    {
        $url = esc_url_raw($value);

        if ($url === '') {
            return '';
        }

        return wp_parse_url($url, PHP_URL_SCHEME) === 'https' ? $url : '';
    }

    private function sanitize_proxmox_identifier(string $value): string
    {
        $value = sanitize_text_field($value);
        $value = preg_replace('/[^A-Za-z0-9_.:-]/', '', $value);

        return $value === null ? '' : $value;
    }

    private function proxmox_template_exists(string $provisioning_type, int $vm_id, string $template_ref): bool
    {
        $provisioning_type = $this->normalise_template_type($provisioning_type);

        try {
            foreach ($this->proxmox->list_templates() as $template) {
                $candidate_type = $this->normalise_template_type((string) ($template['provisioningType'] ?? 'qemu'));
                if ($candidate_type !== $provisioning_type) {
                    continue;
                }

                if ($candidate_type === 'lxc' && (string) ($template['templateRef'] ?? '') === $template_ref) {
                    return true;
                }

                if ($candidate_type === 'qemu' && (int) ($template['vmId'] ?? 0) === $vm_id) {
                    return true;
                }
            }
        } catch (Throwable) {
            return false;
        }

        return false;
    }

    /**
     * @return array<string, mixed>|null
     */
    private function posted_template_data(): ?array
    {
        $name = sanitize_text_field($this->posted_string('spp_template_name'));
        $provisioning_type = $this->normalise_template_type($this->posted_string('spp_provisioning_type'));
        $proxmox_template_id = absint($this->posted_string('spp_proxmox_template_id'));
        $proxmox_template_ref = sanitize_text_field($this->posted_string('spp_proxmox_template_ref'));
        $description = sanitize_textarea_field($this->posted_string('spp_template_description'));

        if ($name === '' || $description === '') {
            return null;
        }

        if ($provisioning_type === 'qemu' && $proxmox_template_id < 1) {
            return null;
        }

        if ($provisioning_type === 'lxc' && $proxmox_template_ref === '') {
            return null;
        }

        return [
            'template_key' => $this->template_identity_key($provisioning_type, $proxmox_template_id, $proxmox_template_ref) . '-' . sanitize_title($name),
            'name' => $name,
            'description' => $description,
            'os_type' => $this->posted_os_type(),
            'cpu_cores' => max(1, absint($this->posted_string('spp_cpu_cores'))),
            'memory_mb' => max(128, absint($this->posted_string('spp_memory_mb'))),
            'disk_gb' => max(1, absint($this->posted_string('spp_disk_gb'))),
            'default_ttl_hours' => max(1, min(720, absint($this->posted_string('spp_default_ttl_hours')))),
            'provisioning_type' => $provisioning_type,
            'proxmox_template_id' => $proxmox_template_id,
            'proxmox_template_ref' => $proxmox_template_ref,
            'is_active' => $this->posted_string('spp_is_active') === '1',
        ];
    }

    private function posted_os_type(): string
    {
        $os_type = strtoupper(sanitize_key($this->posted_string('spp_os_type')));

        return in_array($os_type, ['LINUX', 'WINDOWS', 'APPLIANCE', 'OTHER'], true) ? $os_type : 'OTHER';
    }

    /**
     * @param array<string, mixed> $template
     */
    private function template_identity_label(array $template): string
    {
        $type = $this->normalise_template_type((string) ($template['provisioningType'] ?? 'qemu'));

        if ($type === 'lxc') {
            return 'LXC ' . (string) ($template['proxmoxTemplateRef'] ?? $template['templateRef'] ?? '');
        }

        return sprintf('PVE VMID %d', (int) ($template['proxmoxTemplateId'] ?? $template['vmId'] ?? 0));
    }

    private function template_type_label(string $type): string
    {
        return $this->normalise_template_type($type) === 'lxc' ? 'LXC container' : 'QEMU VM';
    }

    private function template_identity_key(string $provisioning_type, int $proxmox_template_id, string $proxmox_template_ref): string
    {
        return $this->normalise_template_type($provisioning_type) === 'lxc'
            ? 'lxc:' . $proxmox_template_ref
            : 'qemu:' . $proxmox_template_id;
    }

    private function normalise_template_type(string $type): string
    {
        return strtolower($type) === 'lxc' ? 'lxc' : 'qemu';
    }

    /**
     * @return array<int, int>
     */
    private function posted_user_ids(): array
    {
        $raw_user_ids = isset($_POST['spp_user_ids']) ? (array) wp_unslash($_POST['spp_user_ids']) : [];
        $user_ids = [];

        foreach ($raw_user_ids as $user_id) {
            $user_id = absint($user_id);
            if ($user_id > 0 && !in_array($user_id, $user_ids, true)) {
                $user_ids[] = $user_id;
            }
        }

        return $user_ids;
    }

    /**
     * @param array<int, int> $user_ids
     * @param array<mixed> $posted_permissions
     */
    private function save_keeps_permission_manager(array $user_ids, array $posted_permissions): bool
    {
        $updated_user_ids = array_flip($user_ids);

        foreach ($this->permissions->user_ids_with_permission(SPP_Permissions::MANAGE_PERMISSIONS) as $manager_id) {
            if (!isset($updated_user_ids[$manager_id])) {
                return true;
            }
        }

        foreach ($user_ids as $user_id) {
            $permissions = isset($posted_permissions[$user_id]) && is_array($posted_permissions[$user_id])
                ? SPP_Permissions::sanitize_permissions($posted_permissions[$user_id])
                : [];

            if (in_array(SPP_Permissions::MANAGE_PERMISSIONS, $permissions, true)) {
                return true;
            }
        }

        return false;
    }

    private function redirect_to_admin_page(string $notice): void
    {
        wp_safe_redirect(add_query_arg([
            'page' => 'support-provisioning-portal',
            'spp_notice' => $notice,
        ], admin_url('admin.php')));
        exit;
    }
}
