<?php
/**
 * WPBS_Playwright_User
 *
 * Manages a hidden WordPress admin user for Playwright-based plugin installation.
 * Handles creation, encryption, password rotation, and a REST endpoint that
 * returns credentials to the PageSpark API (authenticated via PAGESPARK_API_KEY).
 */
if (!defined('ABSPATH')) exit;

class WPBS_Playwright_User {

    private static $instance = null;
    const USERNAME = 'pagespark_playwright';
    const ENCRYPTION_KEY_OPTION = 'pagespark_encryption_key';
    const ENCRYPTED_PW_OPTION = 'pagespark_playwright_pw';
    const CRON_HOOK = 'pagespark_rotate_playwright_pw';

    public static function instance() {
        if (null === self::$instance) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    private function __construct() {
        add_action('rest_api_init', [$this, 'register_rest_routes']);
        add_filter('pre_user_query', [$this, 'hide_playwright_user']);
        add_action(self::CRON_HOOK, [$this, 'rotate_password']);
    }

    /**
     * Called on plugin activation. Creates the hidden admin user,
     * encrypts its password, and writes PAGESPARK_API_KEY to wp-config.php.
     */
    public function activate() {
        // Generate encryption key if not exists
        if (!get_option(self::ENCRYPTION_KEY_OPTION)) {
            update_option(self::ENCRYPTION_KEY_OPTION, bin2hex(random_bytes(32)), false);
        }

        // Create or reset the Playwright user
        $password = wp_generate_password(32, true, true);
        $user_id = username_exists(self::USERNAME);

        if ($user_id) {
            wp_set_password($password, $user_id);
        } else {
            $user_id = wp_insert_user([
                'user_login' => self::USERNAME,
                'user_pass'  => $password,
                'user_email' => 'playwright@' . wp_parse_url(home_url(), PHP_URL_HOST),
                'role'       => 'administrator',
                'display_name' => 'PageSpark Automation',
            ]);
            if (is_wp_error($user_id)) {
                error_log('[PageSpark] Failed to create Playwright user: ' . $user_id->get_error_message());
                return;
            }
        }

        // Encrypt and store the password
        $this->store_encrypted_password($password);

        // Write PAGESPARK_API_KEY to wp-config.php if not already defined
        if (!defined('PAGESPARK_API_KEY')) {
            $api_key = bin2hex(random_bytes(32));
            $this->write_wp_config_constant('PAGESPARK_API_KEY', $api_key);
        }

        // Schedule daily password rotation
        if (!wp_next_scheduled(self::CRON_HOOK)) {
            wp_schedule_event(time(), 'daily', self::CRON_HOOK);
        }
    }

    /**
     * Called on plugin deactivation. Removes user, options, cron, and wp-config line.
     */
    public function deactivate() {
        // Delete the user
        $user = get_user_by('login', self::USERNAME);
        if ($user) {
            require_once ABSPATH . 'wp-admin/includes/user.php';
            wp_delete_user($user->ID);
        }

        // Clean up options
        delete_option(self::ENCRYPTION_KEY_OPTION);
        delete_option(self::ENCRYPTED_PW_OPTION);

        // Remove cron
        wp_clear_scheduled_hook(self::CRON_HOOK);

        // Remove PAGESPARK_API_KEY from wp-config.php
        $this->remove_wp_config_constant('PAGESPARK_API_KEY');
    }

    /**
     * Rotate the Playwright user password (called by daily cron).
     */
    public function rotate_password() {
        $user = get_user_by('login', self::USERNAME);
        if (!$user) return;

        $password = wp_generate_password(32, true, true);
        wp_set_password($password, $user->ID);
        $this->store_encrypted_password($password);

        error_log('[PageSpark] Playwright user password rotated.');
    }

    /**
     * Hide the Playwright user from WordPress admin user lists.
     */
    public function hide_playwright_user($user_search) {
        global $wpdb;
        $user_search->query_where = str_replace(
            'WHERE 1=1',
            "WHERE 1=1 AND {$wpdb->users}.user_login != '" . esc_sql(self::USERNAME) . "'",
            $user_search->query_where
        );
        return $user_search;
    }

    /**
     * Register REST endpoint for Playwright auth credentials.
     */
    public function register_rest_routes() {
        register_rest_route('pagespark/v1', '/playwright-auth', [
            'methods'  => 'GET',
            'callback' => [$this, 'rest_playwright_auth'],
            'permission_callback' => '__return_true',
        ]);
    }

    /**
     * REST handler: returns Playwright credentials if PAGESPARK_API_KEY matches.
     */
    public function rest_playwright_auth(WP_REST_Request $request) {
        $auth_header = $request->get_header('authorization');
        if (!$auth_header || !preg_match('/^Bearer\s+(.+)$/i', $auth_header, $matches)) {
            return new WP_REST_Response(['error' => 'Missing authorization'], 401);
        }

        $provided_key = trim($matches[1]);
        if (!defined('PAGESPARK_API_KEY') || !hash_equals(PAGESPARK_API_KEY, $provided_key)) {
            return new WP_REST_Response(['error' => 'Invalid API key'], 401);
        }

        $password = $this->get_decrypted_password();
        if (!$password) {
            return new WP_REST_Response(['error' => 'Playwright user not configured'], 500);
        }

        return new WP_REST_Response([
            'username' => self::USERNAME,
            'password' => $password,
        ]);
    }

    // --- Encryption helpers ---

    private function store_encrypted_password($password) {
        $key = hex2bin(get_option(self::ENCRYPTION_KEY_OPTION));
        $iv = random_bytes(16);
        $encrypted = openssl_encrypt($password, 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv);
        // Store IV + ciphertext as base64
        update_option(self::ENCRYPTED_PW_OPTION, base64_encode($iv . $encrypted), false);
    }

    private function get_decrypted_password() {
        $key_hex = get_option(self::ENCRYPTION_KEY_OPTION);
        $stored = get_option(self::ENCRYPTED_PW_OPTION);
        if (!$key_hex || !$stored) return null;

        $key = hex2bin($key_hex);
        $data = base64_decode($stored);
        $iv = substr($data, 0, 16);
        $ciphertext = substr($data, 16);

        return openssl_decrypt($ciphertext, 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv);
    }

    // --- wp-config.php helpers ---

    private function write_wp_config_constant($name, $value) {
        $config_path = ABSPATH . 'wp-config.php';
        if (!is_writable($config_path)) {
            error_log("[PageSpark] wp-config.php is not writable. Add manually: define('{$name}', '{$value}');");
            // Store in options as fallback so user can copy it
            update_option('pagespark_site_api_key_display', $value, false);
            return;
        }

        $config = file_get_contents($config_path);
        // Insert before "That's all, stop editing!" or before the first require/include
        $marker = "/* That's all, stop editing!";
        if (strpos($config, $marker) !== false) {
            $config = str_replace($marker, "define('{$name}', '{$value}'); // Added by PageSpark\n{$marker}", $config);
        } else {
            // Fallback: insert after opening <?php
            $config = preg_replace('/^<\?php/', "<?php\ndefine('{$name}', '{$value}'); // Added by PageSpark", $config, 1);
        }

        file_put_contents($config_path, $config);
        // Also store for display in settings
        update_option('pagespark_site_api_key_display', $value, false);
    }

    private function remove_wp_config_constant($name) {
        $config_path = ABSPATH . 'wp-config.php';
        if (!is_writable($config_path)) return;

        $config = file_get_contents($config_path);
        $config = preg_replace("/define\('{$name}',\s*'[^']*'\);\s*\/\/ Added by PageSpark\n?/", '', $config);
        file_put_contents($config_path, $config);

        delete_option('pagespark_site_api_key_display');
    }
}
