<?php
/*
Plugin Name: WP DevOps Dashboard
Description: A WordPress DevOps dashboard: manage system packages, run Ansible playbooks, control Docker containers, and monitor your server — all via SSH.
Version: 2.2.0
Author: Tlloancy (in zusammenarbeit mit xAI)
License: GPL-2.0+
License URI: https://www.gnu.org/licenses/gpl-2.0.html
Text Domain: package-installator
Domain Path: /languages
*/

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

// === Gestion session intelligente ===
function wpkginst_maybe_start_session() {
    $needed_pages = ['wpkginst-terminal', 'wpkginst-log'];
    if (isset($_GET['page']) && in_array($_GET['page'], $needed_pages, true)) {
        if (session_status() === PHP_SESSION_NONE) {
            session_start();
        }
    }
}
add_action('admin_init', 'wpkginst_maybe_start_session');

add_action('shutdown', function() {
    if (session_status() === PHP_SESSION_ACTIVE) {
        session_write_close();
    }
});

define('WPKGINST_PLUGIN_DIR', plugin_dir_path(__FILE__));
define('WPKGINST_PLUGIN_URL', plugin_dir_url(__FILE__));

require_once WPKGINST_PLUGIN_DIR . 'vendor/autoload.php';
use phpseclib3\Net\SSH2;
use phpseclib3\Crypt\PublicKeyLoader;

require_once WPKGINST_PLUGIN_DIR . 'includes/ssh-handler.php';
require_once WPKGINST_PLUGIN_DIR . 'includes/ajax-handlers.php';
require_once WPKGINST_PLUGIN_DIR . 'includes/system-checker.php';
require_once WPKGINST_PLUGIN_DIR . 'includes/automation-handler.php';

function wpkginst_enqueue_assets() {
    $current_page = isset($_GET['page']) ? sanitize_text_field(wp_unslash($_GET['page'])) : '';

    // CSS needed on both the dashboard and the settings page
    if (in_array($current_page, ['wpkginst-package-manager', 'wpkginst-settings'], true)) {
        wp_enqueue_style('tailwind', WPKGINST_PLUGIN_URL . 'assets/css/tailwind.min.css', [], '2.2.19');
        wp_enqueue_style('wpkginst-styles', WPKGINST_PLUGIN_URL . 'assets/css/styles.css', ['tailwind'], '1.0.0');
    }

    // Settings page only needs the auth-type toggle — no React, no SSH readiness check
    if ($current_page === 'wpkginst-settings') {
        wp_add_inline_script(
            'jquery',
            "jQuery(document).ready(function($) {
                $('input[name=\"wpkginst_ssh_auth_type\"]').on('change', function() {
                    if ($(this).val() === 'key') {
                        $('#wpkginst_ssh_private_key_row').show();
                        $('#wpkginst_ssh_password_row').hide();
                    } else {
                        $('#wpkginst_ssh_private_key_row').hide();
                        $('#wpkginst_ssh_password_row').show();
                    }
                });
            });",
            'after'
        );
        return;
    }

    // Main dashboard — React app + readiness check (SSH calls happen here, not on settings)
    if ($current_page === 'wpkginst-package-manager') {
        wp_enqueue_script('react', WPKGINST_PLUGIN_URL . 'assets/js/vendor/react.min.js', [], '18.2.0', true);
        wp_enqueue_script('react-dom', WPKGINST_PLUGIN_URL . 'assets/js/vendor/react-dom.min.js', ['react'], '18.2.0', true);
        wp_enqueue_script('axios', WPKGINST_PLUGIN_URL . 'assets/js/vendor/axios.min.js', [], '1.6.0', true);
        wp_enqueue_script(
            'react-select',
            WPKGINST_PLUGIN_URL . 'assets/js/vendor/react-select.min.js',
            ['react'],
            '5.8.0',
            ['in_footer' => true, 'strategy' => 'defer', 'type' => 'module']
        );
        wp_enqueue_script(
            'wpkginst-package-manager',
            WPKGINST_PLUGIN_URL . 'assets/js/package-manager.js',
            ['react', 'react-dom', 'axios', 'react-select'],
            '1.0.0',
            ['in_footer' => true, 'strategy' => 'defer', 'type' => 'module']
        );

        $readiness = wpkginst_get_automation_readiness();

        wp_localize_script('wpkginst-package-manager', 'wpkginstAjax', [
            'ajax_url'  => admin_url('admin-ajax.php'),
            'nonce'     => wp_create_nonce('wpkginst_nonce'),
            'restNonce' => wp_create_nonce('wp_rest'),
            'readiness' => $readiness,
        ]);
    }
}
add_action('admin_enqueue_scripts', 'wpkginst_enqueue_assets');

add_filter('script_loader_tag', function ($tag, $handle) {
    if (in_array($handle, ['react-select', 'wpkginst-package-manager'], true)) {
        return str_replace('<script ', '<script type="module" defer ', $tag);
    }
    return $tag;
}, 10, 2);

function wpkginst_admin_menu() {
    add_menu_page(esc_html__('WP DevOps Dashboard', 'package-installator'), esc_html__('WP DevOps Dashboard', 'package-installator'), 'manage_options', 'wpkginst-package-manager', 'wpkginst_admin_page', 'dashicons-admin-tools', 80);
    add_submenu_page('wpkginst-package-manager', esc_html__('SSH Settings', 'package-installator'), esc_html__('SSH Settings', 'package-installator'), 'manage_options', 'wpkginst-settings', 'wpkginst_settings_page');
    add_submenu_page('wpkginst-package-manager', esc_html__('Terminal SSH', 'package-installator'), esc_html__('Terminal SSH', 'package-installator'), 'manage_options', 'wpkginst-terminal', 'wpkginst_terminal_page');
    add_submenu_page('wpkginst-package-manager', esc_html__('Command Log', 'package-installator'), esc_html__('Command Log', 'package-installator'), 'manage_options', 'wpkginst-log', 'wpkginst_log_page');
}
add_action('admin_menu', 'wpkginst_admin_menu');

function wpkginst_admin_page() {
    ?>
    <div class="wrap">
        <h1><?php echo esc_html(get_admin_page_title()); ?></h1>
        <div id="wpkginst-package-manager"></div>
    </div>
    <?php
}

function wpkginst_settings_page() {
    if (isset($_POST['wpkginst_save_settings'])) {
        check_admin_referer('wpkginst_save_settings_nonce');

        $ssh_host = isset( $_POST['wpkginst_ssh_host'] ) ? sanitize_text_field( wp_unslash( $_POST['wpkginst_ssh_host'] ) ) : '';
        $ssh_user = isset( $_POST['wpkginst_ssh_username'] ) ? sanitize_text_field( wp_unslash( $_POST['wpkginst_ssh_username'] ) ) : '';
        $ssh_port = isset( $_POST['wpkginst_ssh_port'] ) ? absint( $_POST['wpkginst_ssh_port'] ) : 22;

        update_option( 'wpkginst_ssh_host', $ssh_host );
        update_option( 'wpkginst_ssh_username', $ssh_user );
        update_option( 'wpkginst_ssh_port', $ssh_port );

        $auth_type = isset($_POST['wpkginst_ssh_auth_type']) ? sanitize_text_field(wp_unslash($_POST['wpkginst_ssh_auth_type'])) : '';
        update_option('wpkginst_ssh_auth_type', $auth_type);

        if ($auth_type === 'key') {
            if (!empty($_POST['wpkginst_ssh_private_key'])) {
                update_option('wpkginst_ssh_private_key', sanitize_textarea_field(wp_unslash($_POST['wpkginst_ssh_private_key'])));
            }
        } else {
            if (!empty($_POST['wpkginst_ssh_password'])) {
                update_option('wpkginst_ssh_password', sanitize_text_field(wp_unslash($_POST['wpkginst_ssh_password'])));
            }
        }
        echo '<div class="notice notice-success is-dismissible"><p>' . esc_html__('Settings saved.', 'package-installator') . '</p></div>';
    }

    $auth_type  = get_option('wpkginst_ssh_auth_type', 'key');
    $has_key    = !empty(get_option('wpkginst_ssh_private_key'));
    $has_pass   = !empty(get_option('wpkginst_ssh_password'));
    $test_nonce = wp_create_nonce('wpkginst_nonce');
    ?>
    <div class="wrap">
        <h1><?php echo esc_html(get_admin_page_title()); ?></h1>

        <div style="max-width:800px;">

            <!-- Live connection status card -->
            <div style="margin-bottom:20px; background:#111827; border-radius:12px; border:1px solid #1f2937; padding:16px 20px; display:flex; align-items:center; justify-content:space-between;">
                <div style="display:flex; align-items:center; gap:12px;">
                    <span id="wpkginst-ssh-dot" style="width:10px; height:10px; border-radius:50%; background:#6b7280; display:inline-block; flex-shrink:0;"></span>
                    <div>
                        <div style="font-size:10px; font-weight:800; text-transform:uppercase; letter-spacing:.15em; color:#4b5563; margin-bottom:2px;">SSH Connection</div>
                        <div id="wpkginst-ssh-msg" style="font-family:monospace; font-size:13px; color:#9ca3af;">Checking connection...</div>
                    </div>
                </div>
                <button id="wpkginst-test-btn" type="button" style="display:flex; align-items:center; gap:8px; background:#2563eb; color:#fff; font-size:11px; font-weight:700; padding:8px 16px; border-radius:8px; border:none; cursor:pointer; transition:background .2s;">
                    <span id="wpkginst-test-spinner" style="display:none; width:12px; height:12px; border-radius:50%; border:2px solid #fff; border-top-color:transparent; animation:wpkginst-spin 0.7s linear infinite;"></span>
                    <?php esc_html_e('Test Connection', 'package-installator'); ?>
                </button>
            </div>
            <style>@keyframes wpkginst-spin { to { transform: rotate(360deg); } }</style>

            <form method="post" action="">
                <?php wp_nonce_field('wpkginst_save_settings_nonce'); ?>

                <!-- SSH Credentials card -->
                <div style="background:#fff; border-radius:12px; border:1px solid #e2e8f0; box-shadow:0 1px 3px rgba(0,0,0,.06); margin-bottom:16px; overflow:hidden;">
                    <div style="padding:14px 20px; border-bottom:1px solid #f1f5f9; background:#f8fafc;">
                        <h2 style="margin:0; font-size:11px; font-weight:800; text-transform:uppercase; letter-spacing:.15em; color:#475569;"><?php esc_html_e('SSH Credentials', 'package-installator'); ?></h2>
                    </div>
                    <div style="padding: 4px 20px 8px;">
                    <table class="form-table" style="margin:0;">
                        <tr>
                            <th><label for="wpkginst_ssh_host"><?php esc_html_e('Host', 'package-installator'); ?></label></th>
                            <td><input type="text" id="wpkginst_ssh_host" name="wpkginst_ssh_host" value="<?php echo esc_attr(get_option('wpkginst_ssh_host', 'localhost')); ?>" class="regular-text"></td>
                        </tr>
                        <tr>
                            <th><label for="wpkginst_ssh_username"><?php esc_html_e('Username', 'package-installator'); ?></label></th>
                            <td><input type="text" id="wpkginst_ssh_username" name="wpkginst_ssh_username" value="<?php echo esc_attr(get_option('wpkginst_ssh_username', 'root')); ?>" class="regular-text"></td>
                        </tr>
                        <tr>
                            <th><label for="wpkginst_ssh_port"><?php esc_html_e('Port', 'package-installator'); ?></label></th>
                            <td><input type="number" id="wpkginst_ssh_port" name="wpkginst_ssh_port" value="<?php echo esc_attr(get_option('wpkginst_ssh_port', 22)); ?>" class="regular-text"></td>
                        </tr>
                        <tr>
                            <th><label><?php esc_html_e('Authentication', 'package-installator'); ?></label></th>
                            <td>
                                <label style="margin-right:16px;"><input type="radio" name="wpkginst_ssh_auth_type" value="key" <?php checked($auth_type, 'key'); ?>> <?php esc_html_e('Private Key', 'package-installator'); ?></label>
                                <label><input type="radio" name="wpkginst_ssh_auth_type" value="password" <?php checked($auth_type, 'password'); ?>> <?php esc_html_e('Password', 'package-installator'); ?></label>
                            </td>
                        </tr>
                        <tr id="wpkginst_ssh_private_key_row" style="<?php echo $auth_type === 'key' ? '' : 'display:none;'; ?>">
                            <th><label for="wpkginst_ssh_private_key"><?php esc_html_e('Private Key', 'package-installator'); ?></label></th>
                            <td>
                                <textarea id="wpkginst_ssh_private_key" name="wpkginst_ssh_private_key" rows="5" cols="50" class="large-text" style="font-family:monospace; padding:8px 12px;" placeholder="<?php echo $has_key ? esc_attr__('Key already saved — leave blank to keep it unchanged', 'package-installator') : esc_attr__('Paste your private key here...', 'package-installator'); ?>"></textarea>
                            </td>
                        </tr>
                        <tr id="wpkginst_ssh_password_row" style="<?php echo $auth_type === 'password' ? '' : 'display:none;'; ?>">
                            <th><label for="wpkginst_ssh_password"><?php esc_html_e('Password', 'package-installator'); ?></label></th>
                            <td>
                                <input type="password" id="wpkginst_ssh_password" name="wpkginst_ssh_password" value="" class="regular-text" placeholder="<?php echo $has_pass ? '••••••••' : esc_attr__('Enter password...', 'package-installator'); ?>" autocomplete="new-password">
                            </td>
                        </tr>
                    </table>
                    </div>
                </div>

                <!-- Automation Catalog card -->
                <div style="background:#fff; border-radius:12px; border:1px solid #e2e8f0; box-shadow:0 1px 3px rgba(0,0,0,.06); margin-bottom:24px; overflow:hidden;">
                    <div style="padding:14px 20px; border-bottom:1px solid #f1f5f9; background:#f8fafc;">
                        <h2 style="margin:0 0 2px; font-size:11px; font-weight:800; text-transform:uppercase; letter-spacing:.15em; color:#475569;"><?php esc_html_e('Automation Catalog', 'package-installator'); ?></h2>
                        <p style="margin:0; font-size:12px; color:#94a3b8;"><?php esc_html_e('Point the plugin at your own GitHub fork to use a custom playbook catalog.', 'package-installator'); ?></p>
                    </div>
                    <div style="padding: 4px 20px 8px;">
                    <table class="form-table" style="margin:0;">
                        <tr>
                            <th><label for="wpkginst_automation_repo_url"><?php esc_html_e('Repository URL', 'package-installator'); ?></label></th>
                            <td>
                                <input type="text" id="wpkginst_automation_repo_url" name="wpkginst_automation_repo_url"
                                       value="<?php echo esc_attr(get_option('wpkginst_automation_repo_url', 'https://github.com/elestranobaron/wp-package-installator-playbooks.git')); ?>"
                                       class="regular-text">
                            </td>
                        </tr>
                        <tr>
                            <th><label for="wpkginst_automation_folder_name"><?php esc_html_e('Remote Folder Name', 'package-installator'); ?></label></th>
                            <td>
                                <input type="text" id="wpkginst_automation_folder_name" name="wpkginst_automation_folder_name"
                                       value="<?php echo esc_attr(get_option('wpkginst_automation_folder_name', 'wp-playbooks')); ?>"
                                       class="regular-text">
                                <p class="description"><?php esc_html_e('Temporary folder created on the remote server to clone the repository into.', 'package-installator'); ?></p>
                            </td>
                        </tr>
                    </table>
                    </div>
                </div>

                <input type="hidden" name="wpkginst_save_settings" value="1">
                <?php submit_button(esc_html__('Save Settings', 'package-installator')); ?>
            </form>
        </div>
    </div>

    <script>
    (function() {
        var nonce  = '<?php echo esc_attr( $test_nonce ); ?>';
        var dot    = document.getElementById('wpkginst-ssh-dot');
        var msg    = document.getElementById('wpkginst-ssh-msg');
        var btn    = document.getElementById('wpkginst-test-btn');
        var spin   = document.getElementById('wpkginst-test-spinner');

        function setState(state, text) {
            var colors = { pending: '#6b7280', testing: '#facc15', ok: '#4ade80', error: '#f87171' };
            var glow   = { ok: '0 0 8px #4ade80', error: 'none', testing: 'none', pending: 'none' };
            dot.style.background   = colors[state] || colors.pending;
            dot.style.boxShadow    = glow[state]   || 'none';
            msg.textContent        = text;
            msg.style.color        = state === 'ok' ? '#4ade80' : state === 'error' ? '#f87171' : state === 'testing' ? '#facc15' : '#9ca3af';
        }

        function runTest() {
            setState('testing', '<?php echo esc_js(__('Testing connection...', 'package-installator')); ?>');
            spin.style.display = 'inline-block';
            btn.disabled       = true;

            var fd = new FormData();
            fd.append('action', 'wpkginst_test_connection');
            fd.append('nonce', nonce);

            fetch(ajaxurl, { method: 'POST', body: fd })
                .then(function(r) { return r.json(); })
                .then(function(res) {
                    if (res.success) {
                        setState('ok', res.data.message);
                    } else {
                        setState('error', (res.data && res.data.message) || '<?php echo esc_js(__('Connection failed', 'package-installator')); ?>');
                    }
                })
                .catch(function() {
                    setState('error', '<?php echo esc_js(__('Request failed', 'package-installator')); ?>');
                })
                .finally(function() {
                    spin.style.display = 'none';
                    btn.disabled       = false;
                });
        }

        btn.addEventListener('click', runTest);
        runTest();
    })();
    </script>
    <?php
}

register_activation_hook(__FILE__, 'wpkginst_create_log_table');
function wpkginst_create_log_table() {
    global $wpdb;
    $table = $wpdb->prefix . 'wpkginst_command_log';
    $charset_collate = $wpdb->get_charset_collate();

    $sql = "CREATE TABLE $table (
        id bigint(20) NOT NULL AUTO_INCREMENT,
        user_id bigint(20) UNSIGNED NOT NULL,
        username varchar(60) NOT NULL,
        user_ip varchar(45) NOT NULL,
        command text NOT NULL,
        output longtext NULL,
        success tinyint(1) NOT NULL DEFAULT 1,
        executed_at datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
        PRIMARY KEY (id),
        KEY user_id (user_id),
        KEY executed_at (executed_at)
    ) $charset_collate;";

    require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
    dbDelta($sql);
}

function wpkginst_terminal_page() {
    if (!current_user_can('manage_options')) {
        wp_die(esc_html__('Unauthorized access.', 'package-installator'));
    }

    $authenticated = false;
    if (isset($_POST['wp_password'])) {
        check_admin_referer('wpkginst_terminal_auth');
        $user = wp_get_current_user();
		// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
        if (wp_check_password(wp_unslash($_POST['wp_password']), $user->data->user_pass, $user->ID)) {
            $_SESSION['wpkginst_terminal_ok'] = true;
            session_write_close();
            $authenticated = true;
        } else {
            echo '<div class="notice notice-error"><p>' . esc_html__('Incorrect WordPress password.', 'package-installator') . '</p></div>';
        }
    }

    if (!empty($_SESSION['wpkginst_terminal_ok'])) {
        $authenticated = true;
    }

    if (!$authenticated) {
        ?>
        <div class="wrap">
            <h1><?php esc_html_e('SSH Terminal - Secure Access', 'package-installator'); ?></h1>
            <div class="card max-w-lg mx-auto">
                <form method="post">
                    <?php wp_nonce_field('wpkginst_terminal_auth'); ?>
                    <p>
                        <label><strong><?php esc_html_e('Enter your WordPress password:', 'package-installator'); ?></strong></label><br>
                        <input type="password" name="wp_password" required class="regular-text" autocomplete="current-password">
                    </p>
                    <p>
                        <input type="submit" value="<?php echo esc_attr__('Open Root Terminal', 'package-installator'); ?>" class="button button-primary button-large">
                    </p>
                </form>
            </div>
        </div>
        <?php
        return;
    }
    ?>
    <div class="wrap">
        <h1><?php esc_html_e('Root Command Executor (non-interactive)', 'package-installator'); ?></h1>
        <p><?php esc_html_e('Write your Bash command and click Run.', 'package-installator'); ?></p>
        <textarea id="command-input" style="width:100%; height:200px; font-family: monospace;" placeholder="<?php echo esc_attr__('ex: ls -la /', 'package-installator'); ?>"></textarea>
        <button id="run-btn" class="button button-primary"><?php esc_html_e('Run', 'package-installator'); ?></button>
        <button id="clear-btn" class="button"><?php esc_html_e('Clear Output', 'package-installator'); ?></button>
        <pre id="output" style="background:#000; color:#0f0; padding:10px; height:400px; overflow:auto; margin-top:20px;"></pre>
        <script>
            document.getElementById('run-btn').addEventListener('click', function() {
                const cmd = document.getElementById('command-input').value.trim();
                const output = document.getElementById('output');
                if (!cmd) return;
                output.textContent = '<?php echo esc_js(__('Running command...', 'package-installator')); ?>\n';
                fetch(ajaxurl, {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
                    body: new URLSearchParams({
                        action: 'wpkginst_run_command',
                        command: cmd,
                        nonce: '<?php echo esc_attr ( wp_create_nonce("wpkginst_run_cmd") ); ?>'
                    })
                })
                .then(r => r.json())
                .then(res => {
                    output.textContent += (res.success ? res.data : '<?php echo esc_js(__('ERROR:', 'package-installator')); ?> ' + res.data) + '\n';
                })
                .catch(err => output.textContent += '<?php echo esc_js(__('AJAX Error:', 'package-installator')); ?> ' + err + '\n');
            });
            document.getElementById('clear-btn').addEventListener('click', () => document.getElementById('output').textContent = '');
        </script>
    </div>
    <?php
}

function wpkginst_log_page() {
    if (!current_user_can('manage_options')) {
        wp_die(esc_html__('Unauthorized access.', 'package-installator'));
    }

    global $wpdb;
    $table = $wpdb->prefix . 'wpkginst_command_log';
    //$logs = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM %i ORDER BY executed_at DESC LIMIT %d", $table, 200 ) );
	// 1. On récupère le nom de la table

    // 2. On prépare la requête en injectant la table manuellement
    // (puisqu'on la définit nous-mêmes dans le code, c'est sûr)
    // On utilise esc_sql pour rassurer le scanner sur l'injection de la variable $table_name
    // En mettant le prepare directement dans get_results, le scanner est rassuré
    $logs = $wpdb->get_results(
      $wpdb->prepare(
        "SELECT * FROM " . esc_sql($table) . " ORDER BY executed_at DESC LIMIT %d",
        200
      )
    );

    ?>
    <div class="wrap">
        <h1><?php echo esc_html(get_admin_page_title()); ?></h1>
        <table class="wp-list-table widefat fixed striped">
            <thead>
                <tr>
                    <th><?php esc_html_e('Date/Time', 'package-installator'); ?></th>
                    <th><?php esc_html_e('User', 'package-installator'); ?></th>
                    <th><?php esc_html_e('IP', 'package-installator'); ?></th>
                    <th><?php esc_html_e('Command', 'package-installator'); ?></th>
                    <th><?php esc_html_e('Status', 'package-installator'); ?></th>
                </tr>
            </thead>
            <tbody>
                <?php if ($logs) : foreach ($logs as $log): ?>
                <tr>
                    <td><?php echo esc_html($log->executed_at); ?></td>
                    <td><?php echo esc_html($log->username); ?> (ID: <?php echo esc_html($log->user_id); ?>)</td>
                    <td><?php echo esc_html($log->user_ip); ?></td>
                    <td><code><?php echo esc_html($log->command); ?></code></td>
                    <td><?php echo $log->success ? '<span style="color:green">' . esc_html__('OK', 'package-installator') . '</span>' : '<span style="color:red">' . esc_html__('FAILURE', 'package-installator') . '</span>'; ?></td>
                </tr>
                <?php endforeach; else : ?>
                    <tr><td colspan="5"><?php esc_html_e('No logs found.', 'package-installator'); ?></td></tr>
                <?php endif; ?>
            </tbody>
        </table>
    </div>
    <?php
}

add_action('wp_ajax_wpkginst_test_connection', 'wpkginst_ajax_test_connection');
function wpkginst_ajax_test_connection() {
    check_ajax_referer('wpkginst_nonce', 'nonce');
    if (!current_user_can('manage_options')) {
        wp_send_json_error(['message' => __('Unauthorized.', 'package-installator')]);
        return;
    }
    $result = wpkginst_test_ssh_connection();
    if ($result['success']) {
        wp_send_json_success(['message' => $result['message']]);
    } else {
        wp_send_json_error(['message' => $result['message']]);
    }
}

add_action('wp_ajax_wpkginst_run_command', 'wpkginst_ajax_run_command');
function wpkginst_ajax_run_command() {
    check_ajax_referer('wpkginst_run_cmd', 'nonce');

    if (session_status() === PHP_SESSION_NONE) {
        session_start();
    }

    if (!current_user_can('manage_options') || empty($_SESSION['wpkginst_terminal_ok'])) {
        wpkginst_log_command('ACCESS DENIED', '', false);
        wp_send_json_error(__('Accès refusé - Session expirée.', 'package-installator'));
    }

    session_write_close();
    // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
    $command = isset($_POST['command']) ? trim(wp_unslash($_POST['command'])) : '';
    if (empty($command)) {
        wp_send_json_error(__('Aucune commande fournie.', 'package-installator'));
    }

    $ssh = new SSH2(get_option('wpkginst_ssh_host', 'localhost'), (int)get_option('wpkginst_ssh_port', 22));
    $auth_type = get_option('wpkginst_ssh_auth_type', 'key');

    try {
        $auth = ($auth_type === 'key')
            ? PublicKeyLoader::load(get_option('wpkginst_ssh_private_key'))
            : get_option('wpkginst_ssh_password');

        if ($ssh->login(get_option('wpkginst_ssh_username', 'root'), $auth)) {
            $ssh->setTimeout(300);
            $output = $ssh->exec($command . ' 2>&1');
            $success = true;
        } else {
            $output = 'SSH login failed';
            $success = false;
        }
    } catch (\Exception $e) {
        $output = $e->getMessage();
        $success = false;
    }

    wpkginst_log_command($command, $output, $success);
    wp_send_json_success($output);
}

function wpkginst_log_command($command, $output = '', $success = true) {
    global $wpdb;
    $user = wp_get_current_user();

    $wpdb->insert(
        $wpdb->prefix . 'wpkginst_command_log',
        [
            'user_id'     => $user->ID,
            'username'    => $user->user_login,
            'user_ip'     => isset($_SERVER['REMOTE_ADDR']) ? sanitize_text_field(wp_unslash($_SERVER['REMOTE_ADDR'])) : 'unknown',
            'command'     => $command,
            'output'      => substr($output, 0, 16777215),
            'success'     => $success ? 1 : 0,
            'executed_at' => current_time('mysql')
        ],
        ['%d', '%s', '%s', '%s', '%s', '%d', '%s']
    );
}

add_action('rest_api_init', function () {
    register_rest_route('wpkginst/v1', '/full-status', [
        'methods'             => 'GET',
        'callback'            => 'wpkginst_rest_get_all_data',
        'permission_callback' => function () {
            return current_user_can('manage_options');
        },
    ]);
});

function wpkginst_rest_get_all_data( WP_REST_Request $request ) {
    $skip_packages = (bool) $request->get_param( 'skip_packages' );
    $folder_name   = get_option( 'wpkginst_automation_folder_name', 'wp-playbooks' );
    $manifest_path = '/tmp/' . $folder_name . '/manifest.json';

    // Single SSH round-trip: stats + docker + manifest catalog in one exec.
    // Sections delimited by unique sentinel lines to avoid collisions with JSON output.
    $mega_cmd =
        "cat /etc/os-release | grep '^PRETTY_NAME=' | cut -d= -f2 | tr -d '\"'; echo '---';" .
        "awk '/MemTotal/ {t=$2} /MemAvailable/ {a=$2} END {print t \",\" (t-a) \",\" a}' /proc/meminfo; echo '---';" .
        "df -hP / | awk 'NR==2 {print $2 \",\" $3 \",\" $4 \",\" $5}'; echo '---';" .
        "cut -d' ' -f1 /proc/loadavg;" .
        "echo '###WPKGINST_DOCKER###';" .
        "docker ps -a --format '{{json .}}' 2>/dev/null;" .
        "echo '###WPKGINST_ANSIBLE###';" .
        "cat " . escapeshellarg( $manifest_path ) . " 2>/dev/null";

    $res    = wpkginst_execute_ssh_command( $mega_cmd );
    $ssh_ok = $res['success'];
    $raw    = $ssh_ok ? ( $res['output'] ?? '' ) : '';

    // ── Parse sections ──────────────────────────────────────────────────────
    $parts_docker  = explode( '###WPKGINST_DOCKER###', $raw, 2 );
    $stats_raw     = $parts_docker[0] ?? '';
    $after_docker  = $parts_docker[1] ?? '';

    $parts_ansible = explode( '###WPKGINST_ANSIBLE###', $after_docker, 2 );
    $docker_raw    = $parts_ansible[0] ?? '';
    $ansible_raw   = $parts_ansible[1] ?? '';

    // ── Stats ────────────────────────────────────────────────────────────────
    $stats = [ 'distro' => 'N/A', 'ram' => 'N/A', 'disk' => 'N/A', 'cpu' => 'N/A' ];
    if ( $ssh_ok ) {
        $s = explode( '---', $stats_raw );
        $stats['distro'] = isset( $s[0] ) ? trim( $s[0] ) : 'N/A';
        if ( isset( $s[1] ) ) {
            $rd = explode( ',', trim( $s[1] ) );
            if ( count( $rd ) === 3 ) {
                $stats['ram'] = round( $rd[0] / 1024 ) . ',' . round( $rd[1] / 1024 ) . ',' . round( $rd[2] / 1024 );
            }
        }
        $stats['disk'] = isset( $s[2] ) ? trim( $s[2] ) : 'N/A';
        $stats['cpu']  = isset( $s[3] ) ? trim( $s[3] ) : 'N/A';
    }

    // ── SSH status (derived — no extra connection needed) ────────────────────
    $ssh = [
        'success' => $ssh_ok,
        'message' => $ssh_ok
            /* translators: %s: Linux distro name */
            ? sprintf( __( 'Connected — %s', 'package-installator' ), $stats['distro'] )
            : ( $res['message'] ?? __( 'Connection failed', 'package-installator' ) ),
    ];

    // ── Docker ───────────────────────────────────────────────────────────────
    $docker_result = [];
    if ( $ssh_ok && ! empty( trim( $docker_raw ) ) ) {
        foreach ( explode( "\n", trim( $docker_raw ) ) as $line ) {
            $decoded = json_decode( trim( $line ), true );
            if ( $decoded ) $docker_result[] = $decoded;
        }
    }

    // ── Ansible catalog (read-only — git sync only on explicit SYNC button) ──
    $ansible_result = [];
    if ( $ssh_ok && ! empty( trim( $ansible_raw ) ) ) {
        $content = json_decode( trim( $ansible_raw ), true );
        if ( json_last_error() === JSON_ERROR_NONE ) {
            $ansible_result = $content['packages'] ?? $content['playbooks'] ?? [];
        }
    }

    // ── Packages (lazy — only when accordion is open) ────────────────────────
    $packages_result = [];
    if ( ! $skip_packages && $ssh_ok ) {
        $php_packages = [ 'php-xml', 'php-mbstring', 'php-curl', 'php-mysql', 'php-gd', 'php-imagick', 'php-zip', 'php-intl', 'php-bcmath', 'php-soap', 'php-redis', 'php-memcached', 'php-json', 'php-opcache', 'php-apcu', 'php-uuid', 'php-pgsql', 'php-sqlite3', 'php-ldap', 'php-imap' ];
        foreach ( $php_packages as $pkg ) {
            $status          = wpkginst_get_package_status( $pkg );
            $packages_result[] = [
                'name'      => $pkg,
                'installed' => (bool) $status['installed'],
            ];
        }
    }

    return new WP_REST_Response( [
        'stats'      => $stats,
        'ssh'        => $ssh,
        'packages'   => $packages_result,
        'containers' => $docker_result,
        'ansible'    => $ansible_result,
    ], 200 );
}
