<?php

declare(strict_types=1);

namespace SiteFort\Modules\Firewall\ExtendedProtection;

use SiteFort\Includes\DataDirectoryProtection;
use SiteFort\Includes\FilesystemMutation;
use SiteFort\Includes\HostingPlatform;
use SiteFort\Includes\IpDetector;
use SiteFort\Includes\SafeUnserializer;
use SiteFort\Includes\SitePathResolver;

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

if ( ! class_exists( WafRuntimeStore::class, false ) ) {
    require_once __DIR__ . '/WafRuntimeStore.php';
}

/**
 * Handles installation, removal, and status reporting for the WAF bootstrap layer.
 */
class Manager {

    private const DATA_DIR_NAME = 'sitefort-data';
    private const BOOTSTRAP_FILE = 'bootstrap.php';
    private const CONFIG_FILE = 'waf-config.php';
    private const VERIFY_NONCE_FILE = 'waf-verify-nonces.php';
    private const MUTATION_LOCK_FILE = '.waf-mutation.lock.php';
    private const DB_LOCK_TIMEOUT_SECONDS = 10;
    private const SAFE_BOOTSTRAP_MARKER = 'SITEFORT_WAF_DISABLED_STUB';
    private const DEFAULT_USER_INI_FILE = '.user.ini';
    private const OPTION_MISSING = '__sitefort_missing__';

    private const BOOTSTRAP_VERSION_OPTION = 'sitefort_waf_bootstrap_version';
    private const RUNTIME_ENABLED_OPTION = 'sitefort_waf_runtime_enabled';
    private const RUNTIME_LAYER_OPTION = 'sitefort_waf_runtime_layer';
    private const RUNTIME_MUTATION_OPTION = 'sitefort_waf_runtime_last_mutation';
    private const RUNTIME_TRANSITION_OPTION = 'sitefort_waf_runtime_transition';
    private const CHAINED_PREPEND_OPTION = 'sitefort_waf_chained_prepend_path';
    private const ACTIVATION_PROBE_QUERY = 'sitefort_waf_activation_probe';
    private const ACTIVATION_PROBE_HEADER = 'x-sitefort-waf-active';
    private const ACTIVATION_PROBE_VALUE = '1';
    private const ACTIVATION_PROBE_CACHE_KEY = 'sitefort_waf_probe_result_v2';
    private const ACTIVATION_PROBE_CACHE_TTL = 60;

    private const OPERATION_COOLDOWN_DEFAULT_SECONDS = 5;
    private const OPERATION_RUNTIME_CACHE_SECONDS = 300;
    private const OPERATION_COOLDOWN_MANAGED_SECONDS = 2;

    /**
     * Install methods reported back to the UI.
     */
    public const METHOD_HTACCESS         = 'htaccess';
    public const METHOD_HTACCESS_USER_INI = 'htaccess_user_ini';
    public const METHOD_USER_INI          = 'user_ini';
    public const METHOD_MU_PLUGIN         = 'mu_plugin';

    /**
     * Active enforcement layer, surfaced in the status payload.
     */
    public const LAYER_AUTO_PREPEND = 'auto_prepend';
    public const LAYER_MU_PLUGIN    = 'mu_plugin';
    public const LAYER_NONE         = 'none';

    /**
     * Marker strings used in .htaccess.
     */
    private const HTACCESS_BEGIN = '# BEGIN SiteFort WAF';
    private const HTACCESS_END   = '# END SiteFort WAF';
    private const USER_INI_BEGIN = '; BEGIN SiteFort WAF';
    private const USER_INI_END   = '; END SiteFort WAF';
    private const APACHE_MOD_PHP_IFMODULES = [
        'mod_php5.c',
        'mod_php7.c',
        'mod_php.c',
    ];

    /** @var resource|null */
    private static $mutation_lock_handle = null;
    private static int $mutation_lock_depth = 0;

    private static function server_value( string $key ): string {
        return IpDetector::get_server_value( $key );
    }

    /**
     * Resolve the pre-WordPress runtime storage backend.
     *
     * Filesystem storage is the default for every host, including managed hosts
     * that currently run through the MU early-loader fallback. The mysqli backend
     * is reserved for an explicit host integration where SiteFort's bootstrap is
     * loaded before WordPress and cannot rely on runtime filesystem writes.
     */
    public static function get_runtime_storage_backend(): string {
        $backend = '';

        if ( defined( 'SITEFORT_WAF_RUNTIME_STORAGE_BACKEND' ) ) {
            $backend = (string) constant( 'SITEFORT_WAF_RUNTIME_STORAGE_BACKEND' );
        } else {
            $server_backend = filter_input(
                INPUT_SERVER,
                'SITEFORT_WAF_RUNTIME_STORAGE_BACKEND',
                FILTER_CALLBACK,
                [
                    'options' => 'sanitize_key',
                    'flags'   => FILTER_REQUIRE_SCALAR,
                ]
            );
            if ( is_string( $server_backend ) ) {
                $backend = sanitize_key( $server_backend );
            }
        }

        if ( function_exists( 'apply_filters' ) ) {
            $filtered = apply_filters( 'sitefort_waf_runtime_storage_backend', $backend );
            if ( is_string( $filtered ) ) {
                $backend = $filtered;
            }
        }

        $backend = strtolower( trim( $backend ) );

        return $backend === 'mysqli' ? 'mysqli' : 'filesystem';
    }

    /**
     * Whether the WAF bootstrap should materialize DB-backed runtime payloads.
     */
    public static function should_use_managed_runtime_storage(): bool {
        return self::get_runtime_storage_backend() === 'mysqli';
    }

    /**
     * Resolve the on-disk bootstrap location.
     *
     * Default canonical location: WP_CONTENT_DIR/sitefort-data/bootstrap.php.
     *
     * Override hooks for custom bootstrap locations:
     *   - SITEFORT_WAF_BOOTSTRAP_PATH constant (highest priority, set in
     *     wp-config.php or a host-side loader)
     *   - sitefort_waf_bootstrap_path filter
     *
     * The override moves the bootstrap binary; the data directory and
     * config file stay at their canonical location (WP_CONTENT_DIR/
     * sitefort-data) because Bootstrap.php reads the SITEFORT_WAF_DATA_DIR
     * constant stamped in by build_bootstrap_contents().
     */
    public static function get_bootstrap_path(): string {
        $default = self::get_data_dir() . '/' . self::BOOTSTRAP_FILE;

        if ( defined( 'SITEFORT_WAF_BOOTSTRAP_PATH' ) ) {
            $override = (string) constant( 'SITEFORT_WAF_BOOTSTRAP_PATH' );
            $override = trim( str_replace( "\0", '', $override ) );
            if ( $override !== '' ) {
                return $override;
            }
        }

        if ( function_exists( 'apply_filters' ) ) {
            $filtered = apply_filters( 'sitefort_waf_bootstrap_path', $default );
            if ( is_string( $filtered ) ) {
                $filtered = trim( str_replace( "\0", '', $filtered ) );
                if ( $filtered !== '' ) {
                    return $filtered;
                }
            }
        }

        return $default;
    }

    private static function get_chained_prepend_path(): string {
        // Lockdown managed hosts own the prepend chain themselves. Any
        // chained value previously stored under this option (from earlier
        // SiteFort versions) was the platform's own shared prepend file,
        // and re-including it from inside the bootstrap is both circular
        // and useless to the user. Migrate the stored value off and stop
        // returning it.
        if ( HostingPlatform::is_locked_down_managed() ) {
            if ( get_option( self::CHAINED_PREPEND_OPTION, null ) !== null ) {
                delete_option( self::CHAINED_PREPEND_OPTION );
            }
            return '';
        }

        $path = (string) get_option( self::CHAINED_PREPEND_OPTION, '' );
        return self::normalize_chainable_prepend_path( $path, self::get_bootstrap_path() );
    }

    private static function set_chained_prepend_path( string $path ): void {
        if ( HostingPlatform::is_locked_down_managed() ) {
            delete_option( self::CHAINED_PREPEND_OPTION );
            return;
        }

        $path = self::normalize_chainable_prepend_path( $path, self::get_bootstrap_path() );
        if ( $path === '' ) {
            delete_option( self::CHAINED_PREPEND_OPTION );
            return;
        }

        update_option( self::CHAINED_PREPEND_OPTION, $path, false );
    }

    private static function get_previous_prepend_path( string $bootstrap_path, string $server_type ): string {
        // Managed hosts may expose a platform prepend that already chains
        // into SiteFort; do not preserve it as a user-owned chained prepend.
        if ( HostingPlatform::is_locked_down_managed() ) {
            return '';
        }

        $runtime_path = self::normalize_chainable_prepend_path( (string) ini_get( 'auto_prepend_file' ), $bootstrap_path );
        if ( $runtime_path !== '' ) {
            return $runtime_path;
        }

        $disk_paths = in_array( $server_type, [ 'apache_mod', 'litespeed' ], true )
            ? [ self::foreign_htaccess_prepend_path_on_disk(), self::foreign_user_ini_prepend_path_on_disk() ]
            : [ self::foreign_user_ini_prepend_path_on_disk(), self::foreign_htaccess_prepend_path_on_disk() ];

        foreach ( $disk_paths as $path ) {
            $path = self::normalize_chainable_prepend_path( $path, $bootstrap_path );
            if ( $path !== '' ) {
                return $path;
            }
        }

        return '';
    }

    private static function normalize_chainable_prepend_path( string $path, string $bootstrap_path ): string {
        $path = trim( str_replace( "\0", '', $path ) );
        if ( $path === '' || ! is_file( $path ) || ! is_readable( $path ) ) {
            return '';
        }

        $real_path = realpath( $path );
        if ( ! is_string( $real_path ) || $real_path === '' ) {
            return '';
        }

        if ( self::paths_match_or_same( $real_path, $bootstrap_path ) ) {
            return '';
        }

        return $real_path;
    }

    private static function is_apache_mod_php(): bool {
        if ( strtolower( PHP_SAPI ) === 'apache2handler' ) {
            return true;
        }

        return function_exists( 'apache_get_modules' );
    }

    // ---------------------------------------------------------------
    // Public API
    // ---------------------------------------------------------------

    /**
     * Detect the web server type for WAF bootstrap purposes.
     *
     * Delegates base detection to the central ServerConfigWriter (which
     * handles the admin override, managed-host aliases, LiteSpeed SAPI, and
     * detection order). Then refines the result into the more
     * granular types needed for auto_prepend_file configuration:
     *
     *   apache  -> apache_mod (mod_php) or apache_cgi (CGI/FastCGI)
     *   nginx   -> nginx_fpm
     *   unknown -> iis check, then unknown
     *
     * @return string One of: apache_mod, apache_cgi, litespeed, nginx_fpm, iis, unknown.
     */
    public static function detect_server(): string {
        $base = \SiteFort\Includes\ServerConfigWriter::detect_server();

        switch ( $base ) {
            case 'apache':
                // mod_php can use php_value in .htaccess; CGI/FastCGI must use per-directory ini.
                return self::is_apache_mod_php() ? 'apache_mod' : 'apache_cgi';

            case 'litespeed':
                return 'litespeed';

            case 'nginx':
                return 'nginx_fpm';

            case 'unknown':
            default:
                // ServerConfigWriter does not detect IIS (no rules to generate),
                // but the WAF Manager needs it for manual config instructions.
                $software = self::server_value( 'SERVER_SOFTWARE' );
                if ( stripos( $software, 'microsoft-iis' ) !== false ) {
                    return 'iis';
                }
                return 'unknown';
        }
    }

    /**
     * Serialize bootstrap/config mutations across admin, REST, and cron requests.
     *
     * @param callable    $callback Callback executed while the lock is held.
     * @param string|null $error    Receives a lock failure reason.
     * @return mixed|null
     */
    public static function with_runtime_mutation_lock( callable $callback, ?string &$error = null ) {
        $error = null;

        if ( self::$mutation_lock_depth > 0 ) {
            self::$mutation_lock_depth++;
            try {
                return $callback();
            } finally {
                self::$mutation_lock_depth--;
            }
        }

        $db_lock_name = self::get_mutation_db_lock_name();
        if ( $db_lock_name !== '' ) {
            $db_lock = self::acquire_db_lock( $db_lock_name );
            if ( $db_lock === true ) {
                self::$mutation_lock_depth = 1;

                try {
                    return $callback();
                } finally {
                    self::$mutation_lock_depth = 0;
                    self::release_db_lock( $db_lock_name );
                }
            }

            if ( $db_lock === false ) {
                $error = 'WAF runtime files are currently being updated by another request.';
                return null;
            }
        }

        $data_dir = self::get_data_dir();
        if ( ! self::ensure_data_dir() ) {
            $error = 'Could not create WAF data directory for the filesystem lock.';
            return null;
        }

        $lock_path = $data_dir . '/' . self::MUTATION_LOCK_FILE;
        // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fopen -- flock is required for cross-request serialization.
        $handle = @fopen( $lock_path, 'c+b' );
        if ( ! is_resource( $handle ) ) {
            $error = 'Could not open WAF filesystem lock.';
            return null;
        }

        if ( @filesize( $lock_path ) === 0 ) {
            // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fwrite -- Initializing the lock marker on the lock handle.
            fwrite( $handle, "<?php\n// SiteFort runtime mutation lock.\n" );
            // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fflush -- Ensuring the lock marker is persisted before permissions are applied.
            fflush( $handle );
            FilesystemMutation::apply_file_permissions( $lock_path, 0644 );
        }

        if ( ! flock( $handle, LOCK_EX ) ) {
            // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fclose -- Closing lock handle.
            fclose( $handle );
            $error = 'Could not acquire WAF filesystem lock.';
            return null;
        }

        self::$mutation_lock_handle = $handle;
        self::$mutation_lock_depth  = 1;

        try {
            return $callback();
        } finally {
            self::$mutation_lock_depth  = 0;
            self::$mutation_lock_handle = null;
            flock( $handle, LOCK_UN );
            // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fclose -- Closing lock handle.
            fclose( $handle );
        }
    }

    private static function get_mutation_db_lock_name(): string {
        if ( ! defined( 'ABSPATH' ) ) {
            return '';
        }

        return 'sitefort_waf_runtime_' . substr( hash( 'sha256', ABSPATH ), 0, 40 );
    }

    private static function acquire_db_lock( string $lock_name ): ?bool {
        global $wpdb;

        if ( ! $wpdb instanceof \wpdb ) {
            return null;
        }

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- MySQL GET_LOCK() is a session-level RPC for cross-request mutex; it is not a table query and caching the result would defeat the lock semantics.
        $result = $wpdb->get_var(
            $wpdb->prepare(
                'SELECT GET_LOCK(%s, %d)',
                $lock_name,
                self::DB_LOCK_TIMEOUT_SECONDS
            )
        );

        if ( (string) $result === '1' ) {
            return true;
        }

        if ( (string) $result === '0' ) {
            return false;
        }

        return null;
    }

    private static function release_db_lock( string $lock_name ): void {
        global $wpdb;

        if ( ! $wpdb instanceof \wpdb ) {
            return;
        }

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- MySQL RELEASE_LOCK() is a session-level RPC paired with GET_LOCK(); not a table query and not cacheable.
        $wpdb->get_var(
            $wpdb->prepare(
                'SELECT RELEASE_LOCK(%s)',
                $lock_name
            )
        );
    }

    /**
     * Install the extended WAF protection.
     *
     * 1. Creates the data directory.
     * 2. Copies Bootstrap.php into the data directory.
     * 3. Writes the initial WAF config via ConfigWriter.
     * 4. Configures auto_prepend_file via .htaccess or per-directory ini.
     *
     * @return array{success: bool, method?: string, error?: string}
     */
    public static function install(): array {
        return self::set_desired_active( true );
    }

    /**
     * Persist the requested WAF state and reconcile disk/runtime artifacts.
     *
     * Host-level PHP startup changes may remain cached after the filesystem
     * mutation succeeds. That cache window is internal convergence state; it
     * must not reject a later user intent. Same-target requests are idempotent,
     * and opposite-target requests supersede the previous transition under the
     * mutation lock.
     *
     * @return array{success: bool, method?: string, already_uninstalled?: bool, error?: string}
     */
    public static function set_desired_active( bool $desired_active ): array {
        $lock_error = null;
        $result = self::with_runtime_mutation_lock(
            static function () use ( $desired_active ): array {
                $cooldown = self::get_runtime_transition_guard();
                $target_operation = $desired_active ? 'install' : 'uninstall';

                if ( ! empty( $cooldown['active'] ) && (string) ( $cooldown['operation'] ?? '' ) === $target_operation ) {
                    if ( ! $desired_active && self::deactivation_cleanup_required_on_disk() ) {
                        return self::uninstall_locked();
                    }

                    return [
                        'success' => true,
                        'method'  => sanitize_key( (string) ( $cooldown['method'] ?? '' ) ),
                    ];
                }

                if ( ! empty( $cooldown['active'] ) ) {
                    self::clear_operation_cooldown();
                }

                return $desired_active ? self::install_locked() : self::uninstall_locked();
            },
            $lock_error
        );

        if ( is_array( $result ) ) {
            return $result;
        }

        return [
            'success' => false,
            'error'   => $lock_error ?: 'Could not acquire WAF filesystem lock.',
        ];
    }

    /**
     * Install the extended WAF protection while the runtime mutation lock is held.
     *
     * @return array{success: bool, method?: string, error?: string}
     */
    private static function install_locked(): array {
        self::reset_probe_cache();

        $data_dir       = self::get_data_dir();
        $bootstrap_src  = __DIR__ . '/Bootstrap.php';
        $bootstrap_dest = self::get_bootstrap_path();
        $server         = self::detect_server();
        $chained_prepend = self::get_previous_prepend_path( $bootstrap_dest, $server );

        // Managed hosts do not expose writable PHP startup configuration.
        if ( HostingPlatform::is_locked_down_managed() ) {
            return self::install_platform_managed_locked( $bootstrap_src, $bootstrap_dest, $chained_prepend );
        }

        if ( in_array( $server, [ 'unknown', 'iis' ], true ) ) {
            return self::install_mu_plugin_fallback_locked( $bootstrap_src, $bootstrap_dest, $chained_prepend );
        }

        // 1. Create data directory.
        if ( ! self::ensure_data_dir() ) {
            return [
                'success' => false,
                'error'   => 'SiteFort could not access the Web Application Firewall data directory.',
            ];
        }

        // Protect the data directory from direct web access.
        self::protect_data_dir( $data_dir );

        // 2. Copy Bootstrap.php to the data directory.
        if ( ! is_file( $bootstrap_src ) ) {
            return [
                'success' => false,
                'error'   => 'SiteFort could not read the Web Application Firewall bootstrap source.',
            ];
        }

        $copy_result = self::copy_bootstrap_file( $bootstrap_src, $bootstrap_dest, $chained_prepend );
        if ( $copy_result !== true ) {
            return [
                'success' => false,
                'error'   => is_string( $copy_result ) ? $copy_result : 'SiteFort could not install the Web Application Firewall bootstrap file.',
            ];
        }

        self::set_chained_prepend_path( $chained_prepend );
        self::mark_bootstrap_version();

        // 3. Write initial config.
        if ( ! ConfigWriter::write() ) {
            return [
                'success' => false,
                'error'   => 'SiteFort could not write the Web Application Firewall runtime configuration.',
            ];
        }

        // 4. Configure the web server to use auto_prepend_file.
        switch ( $server ) {
            case 'apache_mod':
                $result = self::install_htaccess( $bootstrap_dest, $server );
                if ( $result !== true ) {
                    return self::install_fallback_success();
                }
                return self::install_success( self::METHOD_HTACCESS );

            case 'litespeed':
                $result = self::install_htaccess( $bootstrap_dest, $server );
                if ( $result !== true ) {
                    return self::install_fallback_success();
                }

                if ( self::get_user_ini_filename() === '' ) {
                    return self::install_success( self::METHOD_HTACCESS );
                }

                $result = self::install_user_ini( $bootstrap_dest );
                if ( $result !== true ) {
                    return self::install_fallback_success();
                }
                return self::install_success( self::METHOD_HTACCESS_USER_INI );

            case 'apache_cgi':
                $result = self::install_htaccess_user_ini_protection();
                if ( $result !== true ) {
                    return self::install_fallback_success();
                }

                $result = self::install_user_ini( $bootstrap_dest );
                if ( $result !== true ) {
                    return self::install_fallback_success();
                }
                return self::install_success( self::METHOD_USER_INI );

            case 'nginx_fpm':
                if ( self::get_user_ini_filename() === '' ) {
                    return self::install_fallback_success();
                }

                $result = self::install_user_ini( $bootstrap_dest );
                if ( $result !== true ) {
                    return self::install_fallback_success();
                }
                return self::install_success( self::METHOD_USER_INI );

            default:
                return [
                    'success' => false,
                    'error'   => 'Unsupported server type: ' . $server,
                ];
        }
    }

    /**
     * @return array{success: bool, method: string, error?: string}
     */
    private static function install_success( string $method ): array {
        $result = [
            'success' => true,
            'method'  => $method,
        ];
        $runtime_hook_changed = false;

        if ( $method === self::METHOD_MU_PLUGIN ) {
            $deploy = MuPluginLoader::deploy( self::get_bootstrap_path() );
            if ( ! $deploy['success'] ) {
                $error = (string) ( $deploy['error'] ?? 'Could not deploy must-use plugin loader.' );

                return [
                    'success' => false,
                    'error'   => $error,
                    'method'  => $method,
                ];
            }

            $hook_cleanup = self::remove_managed_runtime_hooks();
            $runtime_hook_changed = ! empty( $hook_cleanup['removed_htaccess'] ) || ! empty( $hook_cleanup['removed_user_ini'] );
            if ( ! empty( $hook_cleanup['errors'] ) ) {
                $rollback = MuPluginLoader::remove();
                $error = implode( '; ', $hook_cleanup['errors'] );
                if ( empty( $rollback['success'] ) ) {
                    $error .= ' Rollback failed: ' . (string) ( $rollback['error'] ?? 'Could not remove the Early Loader fallback.' );
                }

                return [
                    'success' => false,
                    'error'   => $error,
                    'method'  => $method,
                ];
            }
        } elseif ( MuPluginLoader::is_installed() ) {
            $runtime_confirmed = self::auto_prepend_runtime_confirmed( self::get_bootstrap_path() );
            $cleanup_requires_active_transport = ! self::can_remove_mu_plugin_without_credentials();
            if ( $runtime_confirmed || ( $cleanup_requires_active_transport && FilesystemMutation::has_configured_write_transport() ) ) {
                $mu_remove = MuPluginLoader::remove();
                if ( empty( $mu_remove['success'] ) ) {
                    $error = (string) ( $mu_remove['error'] ?? 'Could not remove the Early Loader fallback after installing auto-prepend WAF.' );

                    return [
                        'success' => false,
                        'error'   => $error,
                        'method'  => $method,
                    ];
                }
            }
        }

        $layer = $method === self::METHOD_MU_PLUGIN ? self::LAYER_MU_PLUGIN : self::LAYER_AUTO_PREPEND;
        if ( ! self::persist_runtime_state( true, $layer, 'install' ) ) {
            $rollback = self::uninstall_locked();
            $error = 'SiteFort could not persist the Server-Level WAF enabled state.';
            if ( empty( $rollback['success'] ) && ! empty( $rollback['error'] ) ) {
                $error .= ' Rollback failed: ' . (string) $rollback['error'];
            }

            return [
                'success' => false,
                'error'   => $error,
                'method'  => $method,
            ];
        }

        self::reset_probe_cache();
        self::start_operation_cooldown( 'install', $method, $runtime_hook_changed );

        return $result;
    }

    private static function install_fallback_success(): array {
        return self::install_success( self::METHOD_MU_PLUGIN );
    }

    /**
     * Remove SiteFort-managed auto-prepend hooks before installing the MU fallback.
     *
     * @return array{removed_htaccess: bool, removed_user_ini: bool, errors: array<int,string>}
     */
    private static function remove_managed_runtime_hooks(): array {
        $removed_htaccess = false;
        $removed_user_ini = false;
        $errors = [];

        $htaccess = self::get_htaccess_path();
        if ( is_file( $htaccess ) ) {
            $result = self::remove_htaccess_section( $htaccess );
            if ( $result === 'removed' ) {
                $removed_htaccess = true;
            } elseif ( $result !== 'not_present' && $result !== true ) {
                $errors[] = (string) $result;
            }
        }

        $user_ini = self::get_user_ini_path();
        if ( $user_ini !== '' && is_file( $user_ini ) ) {
            $result = self::remove_user_ini_directive( $user_ini );
            if ( $result === 'removed' ) {
                $removed_user_ini = true;
            } elseif ( $result !== 'not_present' && $result !== true ) {
                $errors[] = (string) $result;
            }
        }

        return [
            'removed_htaccess' => $removed_htaccess,
            'removed_user_ini' => $removed_user_ini,
            'errors'           => $errors,
        ];
    }

    private static function install_mu_plugin_fallback_locked( string $bootstrap_src, string $bootstrap_dest, string $chained_prepend ): array {
        $data_dir = self::get_data_dir();
        if ( ! self::ensure_data_dir() ) {
            return [
                'success' => false,
                'error'   => 'SiteFort could not access the Web Application Firewall data directory.',
            ];
        }

        self::protect_data_dir( $data_dir );

        if ( ! is_file( $bootstrap_src ) ) {
            return [
                'success' => false,
                'error'   => 'SiteFort could not read the Web Application Firewall bootstrap source.',
            ];
        }

        $copy_result = self::copy_bootstrap_file( $bootstrap_src, $bootstrap_dest, $chained_prepend );
        if ( $copy_result !== true ) {
            return [
                'success' => false,
                'error'   => is_string( $copy_result ) ? $copy_result : 'SiteFort could not install the Web Application Firewall bootstrap file.',
            ];
        }

        self::set_chained_prepend_path( $chained_prepend );
        self::mark_bootstrap_version();

        if ( ! ConfigWriter::write() ) {
            return [
                'success' => false,
                'error'   => 'SiteFort could not write the Web Application Firewall runtime configuration.',
            ];
        }

        return self::install_success( self::METHOD_MU_PLUGIN );
    }

    /**
     * Install the WAF on a lockdown managed host without writing any
     * auto_prepend_file directive on disk.
     *
     * @return array{success: bool, method?: string, error?: string}
     */
    private static function install_platform_managed_locked( string $bootstrap_src, string $bootstrap_dest, string $chained_prepend ): array {
        return self::install_mu_plugin_fallback_locked( $bootstrap_src, $bootstrap_dest, $chained_prepend );
    }

    /**
     * Uninstall the extended WAF protection.
     *
     * Removes all configuration artifacts:
     *  - .htaccess SiteFort WAF section
     *  - per-directory ini auto_prepend_file directive
     *  - Runtime config, keeping the bootstrap target safe during server refresh
     *  - WAF config file
     *
     * @return array{success: bool, error?: string}
     */
    public static function uninstall( bool $force = false ): array {
        if ( $force ) {
            $lock_error = null;
            $result = self::with_runtime_mutation_lock(
                static function (): array {
                    self::clear_operation_cooldown();
                    return self::uninstall_locked();
                },
                $lock_error
            );

            if ( is_array( $result ) ) {
                return $result;
            }

            return [
                'success' => false,
                'error'   => $lock_error ?: 'Could not acquire WAF filesystem lock.',
            ];
        }

        return self::set_desired_active( false );
    }

    /**
     * Uninstall the extended WAF protection while the runtime mutation lock is held.
     *
     * @return array{success: bool, error?: string}
     */
    private static function uninstall_locked(): array {
        self::reset_probe_cache();

        $errors            = [];
        $config_was_present = false;
        $bootstrap_was_present = false;
        $removed_mu_plugin = false;
        $chained_prepend_path = self::get_chained_prepend_path();
        $bootstrap_path    = self::get_bootstrap_path();
        $runtime_prepend_cached = self::paths_match( (string) ini_get( 'auto_prepend_file' ), $bootstrap_path );

        $hook_cleanup     = self::remove_managed_runtime_hooks();
        $removed_htaccess = $hook_cleanup['removed_htaccess'];
        $removed_user_ini = $hook_cleanup['removed_user_ini'];
        $errors           = array_merge( $errors, $hook_cleanup['errors'] );

        // Delete config so bootstrap becomes a no-op immediately.
        $config = self::get_config_path();
        if ( is_file( $config ) ) {
            $config_was_present = true;
            if ( ! FilesystemMutation::delete_path( $config ) && is_file( $config ) ) {
                $errors[] = 'Could not remove the Web Application Firewall runtime configuration file.';
            }
        }

        $bootstrap_was_present = is_file( $bootstrap_path );
        if ( $bootstrap_was_present || $removed_htaccess || $removed_user_ini || $config_was_present ) {
            if ( ! self::write_safe_bootstrap_stub( $bootstrap_path, $chained_prepend_path ) ) {
                $errors[] = 'Could not write safe bootstrap stub.';
            }
        }

        $verify_nonce_file = self::get_data_dir() . '/' . self::VERIFY_NONCE_FILE;
        if ( is_file( $verify_nonce_file ) ) {
            FilesystemMutation::delete_path( $verify_nonce_file );
        }

        // Remove the must-use plugin loader. Refuses to delete a file
        // that does not carry the SiteFort marker, so unrelated mu-plugins
        // are never touched.
        $mu_plugin_was_present = MuPluginLoader::is_installed();
        if ( $mu_plugin_was_present ) {
            $mu_remove = MuPluginLoader::remove();
            if ( ! $mu_remove['success'] ) {
                $errors[] = (string) ( $mu_remove['error'] ?? 'Could not remove the early-loader must-use plugin.' );
            } else {
                $removed_mu_plugin = ! empty( $mu_remove['removed'] );
            }
        }

        delete_option( self::BOOTSTRAP_VERSION_OPTION );
        if ( ! self::persist_runtime_state( false, self::LAYER_NONE, 'uninstall' ) ) {
            $errors[] = 'Could not persist the Server-Level WAF disabled state.';
        }

        delete_option( self::CHAINED_PREPEND_OPTION );
        delete_option( 'sitefort_waf_policy_signature' );
        $runtime_payload_cleanup = self::delete_runtime_config_payloads();
        if ( ! empty( $runtime_payload_cleanup['errors'] ) ) {
            $errors = array_merge( $errors, $runtime_payload_cleanup['errors'] );
        }

        if ( ! empty( $errors ) ) {
            return [
                'success' => false,
                'error'   => implode( '; ', $errors ),
            ];
        }

        $changed_anything = $removed_htaccess || $removed_user_ini || $config_was_present || $bootstrap_was_present || $removed_mu_plugin;

        if ( $changed_anything ) {
            $runtime_hook_removed = $removed_htaccess || $removed_user_ini || $runtime_prepend_cached;
            self::start_operation_cooldown( 'uninstall', '', $runtime_hook_removed, $runtime_prepend_cached );
        }

        return [
            'success'               => true,
            'already_uninstalled'   => ! $changed_anything,
            'removed_htaccess'      => $removed_htaccess,
            'removed_user_ini'      => $removed_user_ini,
            'removed_mu_plugin'     => $removed_mu_plugin,
            'previous_prepend_path' => $chained_prepend_path,
        ];
    }

    /**
     * Whether install can write either the preferred auto-prepend hook or the fallback loader.
     */
    public static function can_install_without_credentials(): bool {
        $server = self::detect_server();

        $data_dir = self::get_data_dir();
        $data_dir_ready = is_dir( $data_dir )
            ? wp_is_writable( $data_dir )
            : wp_is_writable( dirname( $data_dir ) );
        if ( ! $data_dir_ready ) {
            return false;
        }

        $bootstrap_dest = self::get_bootstrap_path();
        $bootstrap_dir = dirname( $bootstrap_dest );
        $bootstrap_dir_ready = is_dir( $bootstrap_dir )
            ? wp_is_writable( $bootstrap_dir )
            : wp_is_writable( dirname( $bootstrap_dir ) );
        if ( ! $bootstrap_dir_ready ) {
            return false;
        }

        if ( self::can_write_runtime_hook_without_credentials( $server ) ) {
            return self::can_remove_mu_plugin_without_credentials();
        }

        return self::can_deploy_mu_plugin_without_credentials();
    }

    private static function can_write_runtime_hook_without_credentials( string $server ): bool {
        if ( in_array( $server, [ 'unknown', 'iis' ], true ) ) {
            return false;
        }

        if ( in_array( $server, [ 'apache_mod', 'litespeed' ], true ) && ! self::can_directly_rewrite_runtime_file( self::get_htaccess_path() ) ) {
            return false;
        }

        if ( in_array( $server, [ 'apache_cgi', 'nginx_fpm', 'litespeed' ], true ) ) {
            $user_ini = self::get_user_ini_path();
            if ( $user_ini === '' && in_array( $server, [ 'apache_cgi', 'nginx_fpm' ], true ) ) {
                return false;
            }

            if ( $user_ini !== '' && ! self::can_directly_rewrite_runtime_file( $user_ini ) ) {
                return false;
            }
        }

        return true;
    }

    private static function can_deploy_mu_plugin_without_credentials(): bool {
        $path = MuPluginLoader::get_path();
        if ( is_file( $path ) ) {
            $contents = FilesystemMutation::read_file_contents( $path );
            if ( ! is_string( $contents ) || strpos( $contents, MuPluginLoader::VERSION_MARKER ) === false ) {
                return false;
            }

            return wp_is_writable( $path ) || wp_is_writable( dirname( $path ) );
        }

        $directory = MuPluginLoader::get_directory();
        if ( is_dir( $directory ) ) {
            return wp_is_writable( $directory );
        }

        return wp_is_writable( dirname( $directory ) );
    }

    /**
     * Whether uninstall can complete through direct writes without extra credentials.
     */
    public static function can_uninstall_without_credentials(): bool {
        $server = self::detect_server();

        if ( ! in_array( $server, [ 'unknown', 'iis' ], true ) ) {
            $htaccess = self::get_htaccess_path();
            if ( is_file( $htaccess ) && ! self::can_directly_rewrite_runtime_file( $htaccess ) ) {
                return false;
            }

            $user_ini = self::get_user_ini_path();
            if ( $user_ini !== '' && is_file( $user_ini ) && ! self::can_directly_rewrite_runtime_file( $user_ini ) ) {
                return false;
            }
        }

        if ( ! self::can_remove_mu_plugin_without_credentials() ) {
            return false;
        }

        $data_dir = self::get_data_dir();
        if ( is_dir( $data_dir ) && ! wp_is_writable( $data_dir ) ) {
            return false;
        }

        return true;
    }

    private static function can_remove_mu_plugin_without_credentials(): bool {
        if ( ! MuPluginLoader::is_installed() ) {
            return true;
        }

        $path = MuPluginLoader::get_path();
        return wp_is_writable( $path ) || wp_is_writable( dirname( $path ) );
    }

    /**
     * Refresh the deployed bootstrap when the plugin source changes.
     */
    public static function ensure_bootstrap_current(): bool {
        $lock_error = null;
        $result = self::with_runtime_mutation_lock(
            static function (): bool {
                return self::ensure_bootstrap_current_locked();
            },
            $lock_error
        );

        return is_bool( $result ) ? $result : false;
    }

    /**
     * Refresh the deployed bootstrap while the runtime mutation lock is held.
     */
    private static function ensure_bootstrap_current_locked(): bool {
        $bootstrap_path = self::get_bootstrap_path();
        if ( ! is_file( $bootstrap_path ) ) {
            return false;
        }

        if ( self::bootstrap_is_disabled_stub( $bootstrap_path ) ) {
            return false;
        }

        $bootstrap_src = __DIR__ . '/Bootstrap.php';
        if ( ! is_file( $bootstrap_src ) ) {
            return false;
        }

        $source_contents = FilesystemMutation::read_file_contents( $bootstrap_src );
        $target_contents = FilesystemMutation::read_file_contents( $bootstrap_path );
        $chained_prepend_path = self::get_chained_prepend_path();

        if ( ! is_string( $source_contents ) || ! is_string( $target_contents ) ) {
            return false;
        }

        $expected_contents = self::build_bootstrap_contents( $source_contents, $chained_prepend_path, $bootstrap_path );
        $needs_bootstrap_rewrite = ! hash_equals( sha1( $expected_contents ), sha1( $target_contents ) );

        if ( $needs_bootstrap_rewrite ) {
            if ( self::copy_bootstrap_file( $bootstrap_src, $bootstrap_path, $chained_prepend_path ) !== true ) {
                return false;
            }
        }

        self::mark_bootstrap_version();

        if ( self::should_manage_mu_loader() ) {
            if ( MuPluginLoader::needs_update( $bootstrap_path ) ) {
                return ! empty( MuPluginLoader::deploy( $bootstrap_path )['success'] );
            }

            return true;
        }

        if ( MuPluginLoader::is_installed() ) {
            if ( self::should_defer_mu_loader_removal_until_auto_prepend_confirmed( $bootstrap_path ) ) {
                return true;
            }

            return ! empty( MuPluginLoader::remove()['success'] );
        }

        return true;
    }

    /**
     * Get the current status of the extended WAF protection.
     *
     * @return array{
     *   active: bool,
     *   desired_active: bool,
     *   active_layer: 'auto_prepend'|'mu_plugin'|'none',
     *   transition_operation: string,
     *   fallback_context: string,
     *   fallback_message: string|null,
     *   cooldown_active: bool,
     *   cooldown_message: string,
     *   installed_on_disk: bool,
     *   pending_activation: bool,
     *   pending_message: string|null,
     *   activation_failed: bool,
     *   activation_failure_message: string|null,
     *   pending_deactivation: bool,
     *   pending_deactivation_message: string|null,
     *   pending_deactivation_cache_wait: bool,
     *   pending_deactivation_cleanup_required: bool,
     *   manual_deactivation_required: bool,
     *   manual_deactivation_message: string|null,
     *   manual_configuration_required: bool,
     *   manual_configuration_message: string|null,
     *   server_type: string,
     *   bootstrap_exists: bool,
     *   config_exists: bool,
     *   fallback_cleanup_required: bool,
     *   fallback_cleanup_message: string|null,
     *   user_ini_public_protection_required: bool,
     *   user_ini_public_protection_message: string|null,
     *   chained_prepend_path: string
     * }
     */
    public static function get_status(): array {
        $bootstrap_path = self::get_bootstrap_path();
        $prepend_value  = (string) ini_get( 'auto_prepend_file' );
        $chained_prepend_path = self::get_chained_prepend_path();
        $server_type    = self::detect_server();
        $is_locked_down_managed = HostingPlatform::is_locked_down_managed();
        $desired_runtime_enabled = self::get_runtime_desired_enabled();
        $selected_runtime_layer  = self::get_runtime_layer();

        $artifacts = self::runtime_artifact_state( $bootstrap_path );
        $bootstrap_exists = $artifacts['bootstrap_exists'];
        $config_exists = $artifacts['config_exists'];
        $runtime_config_store_exists = $artifacts['runtime_config_store_exists'];
        $runtime_enforceable = $artifacts['runtime_enforceable'];
        $user_ini_directive_exists = $artifacts['user_ini_directive_exists'];
        $directive_exists_on_disk = $artifacts['directive_exists_on_disk'];
        $disabled_hook_on_disk     = $directive_exists_on_disk && $bootstrap_exists && ! $runtime_enforceable;
        $installed_on_disk         = ( $runtime_enforceable && $directive_exists_on_disk );
        $cooldown                  = self::get_runtime_transition_guard();
        $runtime_points_to_bootstrap = self::paths_match( $prepend_value, $bootstrap_path );
        $runtime_matches_bootstrap = false;
        if ( self::should_probe_runtime_activation( $runtime_enforceable, $directive_exists_on_disk, $is_locked_down_managed, $runtime_points_to_bootstrap ) ) {
            $runtime_matches_bootstrap = self::probe_runtime_activation( $bootstrap_path, self::should_use_cached_activation_probe( $cooldown ) ) === true;
        }

        $stale_runtime_prepend     = (
            ! $is_locked_down_managed
            && $runtime_points_to_bootstrap
            && ( ! $directive_exists_on_disk || ! $runtime_enforceable )
        );
        $mu_plugin_installed       = MuPluginLoader::is_installed();
        $waf_desired_off           = ( $desired_runtime_enabled === false );
        $fallback_cleanup_required = false;
        $fallback_cleanup_message  = null;
        if (
            $mu_plugin_installed
            && $selected_runtime_layer === self::LAYER_AUTO_PREPEND
            && ! $waf_desired_off
            && $runtime_enforceable
            && ( $runtime_points_to_bootstrap || $runtime_matches_bootstrap )
        ) {
            $mu_remove = MuPluginLoader::remove();
            if ( ! empty( $mu_remove['success'] ) ) {
                $mu_plugin_installed = false;
            } else {
                $fallback_cleanup_required = true;
                $fallback_cleanup_message = (string) ( $mu_remove['error'] ?? 'Could not remove the Early Loader fallback after auto-prepend became active.' );
            }
        }
        $deactivation_expected     = $waf_desired_off || ( $desired_runtime_enabled === null && ! $runtime_enforceable );

        $pending_activation = (
            ! $waf_desired_off
            && ! $is_locked_down_managed
            && ! $runtime_matches_bootstrap
            && $runtime_enforceable
            && $directive_exists_on_disk
            && ! empty( $cooldown['active'] )
            && (string) $cooldown['operation'] === 'install'
            && ! empty( $cooldown['runtime_cache_window'] )
        );

        $auto_prepend_layer_allowed = ( $selected_runtime_layer !== self::LAYER_MU_PLUGIN );
        $auto_prepend_takeover_fallback_allowed = (
            $selected_runtime_layer === self::LAYER_AUTO_PREPEND
            && $mu_plugin_installed
            && $runtime_enforceable
            && ! $runtime_matches_bootstrap
        );
        $mu_plugin_layer_allowed = ( $selected_runtime_layer !== self::LAYER_AUTO_PREPEND ) || $auto_prepend_takeover_fallback_allowed;

        $detected_mu_plugin_active = $mu_plugin_layer_allowed
            && $mu_plugin_installed
            && $runtime_enforceable
            && ! $runtime_matches_bootstrap;
        $usable_mu_plugin_installed = $mu_plugin_layer_allowed && $mu_plugin_installed;

        $activation_failed = (
            ! $waf_desired_off
            && $runtime_enforceable
            && ! $runtime_matches_bootstrap
            && ! $pending_activation
            && ! $detected_mu_plugin_active
            && (
                ( $directive_exists_on_disk && ! $usable_mu_plugin_installed )
                || ( ! $directive_exists_on_disk && ( $config_exists || $runtime_config_store_exists ) && ! $usable_mu_plugin_installed )
            )
        );

        $manual_configuration_required = (
            ! $waf_desired_off
            && $server_type === 'nginx_fpm'
            && ! $is_locked_down_managed
            && $runtime_enforceable
            && ! $directive_exists_on_disk
            && self::get_user_ini_filename() === ''
            && ! $detected_mu_plugin_active
            && ! $activation_failed
        );
        $pending_message = $pending_activation ? self::build_pending_activation_message() : null;
        $activation_failure_message = $activation_failed ? self::build_activation_failure_message( $server_type, $directive_exists_on_disk ) : null;
        $runtime_detected_active = $runtime_matches_bootstrap || $detected_mu_plugin_active;
        $deactivation_cleanup_required = $deactivation_expected && (
            $runtime_detected_active
            || $runtime_enforceable
            || $runtime_config_store_exists
            || $directive_exists_on_disk
            || $mu_plugin_installed
            || $disabled_hook_on_disk
        );
        $deactivation_cache_wait = $deactivation_expected
            && ! $deactivation_cleanup_required
            && ! empty( $cooldown['active'] )
            && (string) $cooldown['operation'] === 'uninstall';
        $manual_deactivation_required = $deactivation_expected
            && ! $deactivation_cleanup_required
            && ! $deactivation_cache_wait
            && $stale_runtime_prepend;
        $pending_deactivation = $deactivation_cleanup_required || $deactivation_cache_wait;
        $pending_deactivation_message = $pending_deactivation
            ? (
                $deactivation_cleanup_required
                    ? self::build_pending_deactivation_cleanup_message()
                    : ( (string) ( $cooldown['message'] ?? '' ) !== '' ? (string) $cooldown['message'] : self::build_pending_deactivation_message( $cooldown ) )
            )
            : null;
        $manual_configuration_message = $manual_configuration_required
            ? self::build_manual_activation_message( $bootstrap_path )
            : null;
        $transition_operation = $pending_deactivation
            ? 'uninstall'
            : ( $pending_activation ? 'install' : '' );

        if ( ! $pending_deactivation && ! $waf_desired_off && $auto_prepend_layer_allowed && $runtime_matches_bootstrap ) {
            $active_layer = self::LAYER_AUTO_PREPEND;
        } elseif ( ! $pending_deactivation && ! $waf_desired_off && $detected_mu_plugin_active ) {
            $active_layer = self::LAYER_MU_PLUGIN;
        } else {
            $active_layer = self::LAYER_NONE;
        }

        $waf_active = ( $active_layer !== self::LAYER_NONE );
        $computed_desired_active = ! $activation_failed && (
            $waf_active
            || $installed_on_disk
            || $pending_activation
            || $manual_configuration_required
            || $detected_mu_plugin_active
        );
        if ( $pending_deactivation ) {
            $desired_active = false;
        } elseif ( $pending_activation ) {
            $desired_active = true;
        } elseif ( $desired_runtime_enabled !== null ) {
            $desired_active = $desired_runtime_enabled && ! $activation_failed;
        } else {
            $desired_active = $computed_desired_active;
        }

        $fallback_context = $detected_mu_plugin_active && ! $pending_deactivation && ! $waf_desired_off
            ? self::get_fallback_context( $is_locked_down_managed, $installed_on_disk )
            : '';
        $fallback_message = $detected_mu_plugin_active && ! $pending_deactivation && ! $waf_desired_off
            ? self::build_fallback_message( $is_locked_down_managed, HostingPlatform::label(), $installed_on_disk )
            : null;

        return [
            'active'            => $waf_active,
            'desired_active'    => $desired_active,
            'active_layer'      => $active_layer,
            'transition_operation' => $transition_operation,
            'fallback_context'  => $fallback_context,
            'fallback_message'  => $fallback_message,
            'cooldown_active'   => (bool) $cooldown['active'],
            'cooldown_message'  => (string) $cooldown['message'],
            'installed_on_disk' => $installed_on_disk,
            'pending_activation' => $pending_activation,
            'pending_message'   => $pending_message,
            'activation_failed' => $activation_failed,
            'activation_failure_message' => $activation_failure_message,
            'pending_deactivation' => $pending_deactivation,
            'pending_deactivation_message' => $pending_deactivation_message,
            'pending_deactivation_cache_wait' => $deactivation_cache_wait,
            'pending_deactivation_cleanup_required' => $deactivation_cleanup_required,
            'manual_deactivation_required' => $manual_deactivation_required,
            'manual_deactivation_message' => $manual_deactivation_required ? self::build_manual_deactivation_message( $bootstrap_path ) : null,
            'manual_configuration_required' => $manual_configuration_required,
            'manual_configuration_message' => $manual_configuration_message,
            'server_type'       => $server_type,
            'bootstrap_exists'  => $bootstrap_exists,
            'config_exists'     => $config_exists,
            'fallback_cleanup_required' => $fallback_cleanup_required,
            'fallback_cleanup_message' => $fallback_cleanup_message,
            'user_ini_public_protection_required' => self::user_ini_public_protection_required( $server_type, $user_ini_directive_exists ),
            'user_ini_public_protection_message' => self::build_user_ini_public_protection_message( $server_type, $user_ini_directive_exists ),
            'chained_prepend_path' => $chained_prepend_path,
        ];
    }

    private static function get_fallback_context( bool $is_locked_down_managed, bool $installed_on_disk ): string {
        if ( $is_locked_down_managed ) {
            return 'platform_managed';
        }

        return $installed_on_disk ? 'auto_prepend_unconfirmed' : 'auto_prepend_unavailable';
    }

    private static function build_fallback_message( bool $is_locked_down_managed, string $host_label, bool $installed_on_disk ): string {
        if ( $is_locked_down_managed ) {
            $label = trim( $host_label ) !== '' ? trim( $host_label ) : 'Your hosting platform';
            return $label . ' manages PHP startup configuration at the platform level. SiteFort has enabled the Web Application Firewall (WAF) through the WordPress Early Loader fallback.';
        }

        if ( $installed_on_disk ) {
            return 'Server-level activation has not been confirmed yet. SiteFort has enabled the Web Application Firewall (WAF) through the WordPress Early Loader fallback, and the server-level rule will take over automatically once the host applies it.';
        }

        return 'Server-level PHP startup configuration is not available on this host. SiteFort has enabled the Web Application Firewall (WAF) through the WordPress Early Loader fallback.';
    }

    /**
     * Check whether SiteFort's auto_prepend_file directive exists in the active per-directory PHP config.
     */
    private static function user_ini_directive_exists_on_disk(): bool {
        return self::file_contains_bootstrap_directive( self::get_user_ini_path() );
    }

    /**
     * Check whether SiteFort's auto_prepend_file directive exists in .htaccess.
     */
    private static function htaccess_directive_exists_on_disk(): bool {
        return self::file_contains_bootstrap_directive( self::get_htaccess_path() );
    }

    /**
     * Check whether a config file contains SiteFort's bootstrap path.
     *
     * @param string $path Absolute path to the config file.
     */
    private static function file_contains_bootstrap_directive( string $path ): bool {
        $bootstrap_path = self::get_bootstrap_path();
        if ( $path === '' || ! is_file( $path ) || ! is_readable( $path ) ) {
            return false;
        }

        $contents = @file_get_contents( $path );
        if ( $contents === false ) {
            return false;
        }

        return ( strpos( $contents, 'auto_prepend_file' ) !== false && strpos( $contents, $bootstrap_path ) !== false );
    }

    /**
     * Return a non-SiteFort auto_prepend_file value from the active per-directory PHP config.
     */
    private static function foreign_user_ini_prepend_path_on_disk(): string {
        $path = self::get_user_ini_path();
        if ( $path === '' || ! is_file( $path ) || ! is_readable( $path ) ) {
            return '';
        }

        $contents = @file_get_contents( $path );
        if ( $contents === false ) {
            return '';
        }

        $cleaned = self::strip_user_ini_directive( $contents );
        return self::extract_user_ini_prepend_path( $cleaned );
    }

    /**
     * Return a non-SiteFort prepend directive path from .htaccess, if present.
     */
    private static function foreign_htaccess_prepend_path_on_disk(): string {
        $path = self::get_htaccess_path();
        if ( ! is_file( $path ) || ! is_readable( $path ) ) {
            return '';
        }

        $contents = @file_get_contents( $path );
        if ( $contents === false ) {
            return '';
        }

        $cleaned = self::strip_htaccess_section( $contents );
        return self::extract_htaccess_prepend_path( $cleaned );
    }

    private static function user_ini_public_protection_required( string $server_type, bool $user_ini_directive_exists ): bool {
        if ( $server_type !== 'nginx_fpm' || ! $user_ini_directive_exists || self::get_user_ini_filename() === '' ) {
            return false;
        }

        // The deny rule is now contributed to the unified ServerConfigWriter via the
        // sitefort_server_rules_nginx filter. If the managed include file is being
        // persisted by SiteFort, no manual action is needed; only surface the warning
        // when the writer cannot apply rules automatically (manual_only / unsupported).
        if ( class_exists( '\\SiteFort\\Includes\\ServerConfigWriter' ) ) {
            $state = \SiteFort\Includes\ServerConfigWriter::get_state();
            $mode  = (string) ( $state['mode'] ?? '' );
            $auto_modes = [ 'persisted', 'sync_pending', 'repair_pending' ];
            if ( in_array( $mode, $auto_modes, true ) ) {
                return false;
            }
        }

        return true;
    }

    private static function build_user_ini_public_protection_message( string $server_type, bool $user_ini_directive_exists ): ?string {
        if ( ! self::user_ini_public_protection_required( $server_type, $user_ini_directive_exists ) ) {
            return null;
        }

        $public_path = SitePathResolver::get_home_root_file_path( self::get_user_ini_filename() );

        return sprintf(
            'Additional Nginx configuration is required. Add this deny rule to the active server block to protect the Server-Level WAF configuration file from public access: location = %s { deny all; }',
            $public_path
        );
    }

    /**
     * Whether the active WAF installation requires the shared Nginx writer to
     * protect the per-directory PHP config file from public access.
     *
     * This intentionally avoids calling ServerConfigWriter state helpers so the
     * shared rule assembly path cannot recurse back into itself.
     */
    public static function requires_nginx_user_ini_public_deny_rule(): bool {
        if ( self::detect_server() !== 'nginx_fpm' ) {
            return false;
        }

        if ( ! self::user_ini_directive_exists_on_disk() ) {
            return false;
        }

        return self::get_user_ini_filename() !== '';
    }

    private static function build_pending_activation_message(): string {
        $ttl = self::get_user_ini_cache_ttl();
        if ( $ttl > 0 ) {
            return 'Server-Level WAF has been activated. The change will take full effect within a few minutes, once your server reloads its PHP configuration.';
        }

        return 'Server-Level WAF has been activated. Your server is applying the change now.';
    }

    private static function build_activation_failure_message( string $server_type, bool $directive_exists_on_disk ): string {
        if ( ! $directive_exists_on_disk ) {
            return 'Server-Level WAF runtime files are present, but PHP startup enforcement is not configured. Review auto_prepend_file configuration, or toggle off to remove installed WAF files.';
        }

        if ( in_array( $server_type, [ 'apache_mod', 'apache_cgi' ], true ) ) {
            return 'Server-Level WAF files are installed, but SiteFort could not confirm Apache PHP startup enforcement. Review the auto_prepend_file rule, firewall origin enforcement, and WordPress loopback access.';
        }

        if ( $server_type === 'litespeed' ) {
            return 'Server-Level WAF files are installed, but SiteFort could not confirm LiteSpeed PHP startup enforcement. Review LiteSpeed PHP configuration, firewall origin enforcement, and WordPress loopback access.';
        }

        if ( $server_type === 'nginx_fpm' ) {
            return 'Server-Level WAF files are installed, but SiteFort could not confirm PHP-FPM startup enforcement. Review .user.ini or auto_prepend_file configuration, firewall origin enforcement, and WordPress loopback access.';
        }

        return 'Server-Level WAF files are installed, but SiteFort could not confirm PHP startup enforcement. Review PHP auto_prepend_file configuration, firewall origin enforcement, and WordPress loopback access.';
    }

    private static function build_pending_deactivation_message( array $cooldown = [] ): string {
        $seconds = isset( $cooldown['seconds'] ) ? (int) $cooldown['seconds'] : self::get_user_ini_cache_ttl();

        if ( max( 0, $seconds ) > 0 ) {
            return 'Server-Level WAF has been disabled. The change will take full effect within a few minutes, once your server reloads its PHP configuration.';
        }

        return 'Server-Level WAF has been disabled. Your server is applying the change now.';
    }

    private static function build_pending_deactivation_cleanup_message(): string {
        return 'Server-Level WAF removal could not finish because SiteFort startup files remain on this server. Retry removal, or review filesystem permissions if the issue persists.';
    }

    private static function build_manual_deactivation_message( string $bootstrap_path ): string {
        return 'Server-Level WAF is disabled, but PHP is still configured outside SiteFort to load the safety bootstrap. Remove auto_prepend_file = "' . $bootstrap_path . '" from php.ini or your hosting control panel to finish cleanup.';
    }

    private static function build_manual_activation_message( string $bootstrap_path ): string {
        return 'Automatic PHP configuration is not available on this host. Add auto_prepend_file = "' . $bootstrap_path . '" to php.ini or your hosting control panel to finish activating Server-Level WAF.';
    }

    private static function should_probe_runtime_activation(
        bool $runtime_enforceable,
        bool $directive_exists_on_disk,
        bool $is_locked_down_managed = false,
        bool $runtime_points_to_bootstrap = false
    ): bool {
        if ( ! $runtime_enforceable ) {
            return false;
        }

        if ( $is_locked_down_managed ) {
            return true;
        }

        return $directive_exists_on_disk || $runtime_points_to_bootstrap;
    }

    private static function should_use_cached_activation_probe( array $cooldown ): bool {
        return empty( $cooldown['active'] ) || (string) ( $cooldown['operation'] ?? '' ) !== 'install';
    }

    private static function probe_runtime_activation( string $bootstrap_path, bool $use_cache = true ): ?bool {
        $cache_key = self::probe_cache_key( $bootstrap_path );
        if ( $use_cache && $cache_key !== '' && function_exists( 'get_transient' ) ) {
            $cached = get_transient( $cache_key );
            if ( $cached === 'true' ) {
                return true;
            }
            if ( $cached === 'false' ) {
                return false;
            }
        }

        $result = self::probe_runtime_activation_uncached( $bootstrap_path );

        if ( $cache_key !== '' && is_bool( $result ) && ( $use_cache || $result ) && function_exists( 'set_transient' ) ) {
            set_transient( $cache_key, $result ? 'true' : 'false', self::ACTIVATION_PROBE_CACHE_TTL );
        }

        return $result;
    }

    private static function probe_cache_key( string $bootstrap_path ): string {
        if ( $bootstrap_path === '' ) {
            return '';
        }

        return self::ACTIVATION_PROBE_CACHE_KEY . '_' . substr( hash( 'sha256', $bootstrap_path ), 0, 16 );
    }

    private static function reset_probe_cache(): void {
        if ( ! function_exists( 'delete_transient' ) ) {
            return;
        }

        $key = self::probe_cache_key( self::get_bootstrap_path() );
        if ( $key !== '' ) {
            delete_transient( $key );
        }
    }

    private static function calculate_cooldown_seconds(
        string $operation,
        string $method = '',
        bool $runtime_hook_changed = false,
        bool $runtime_prepend_cached = false
    ): int {
        if ( HostingPlatform::is_locked_down_managed() ) {
            return self::OPERATION_COOLDOWN_MANAGED_SECONDS;
        }

        if ( self::operation_has_runtime_cache_window( $operation, $method, $runtime_hook_changed, $runtime_prepend_cached ) ) {
            $ttl = self::get_user_ini_cache_ttl();
            return max( self::OPERATION_RUNTIME_CACHE_SECONDS, $ttl );
        }

        return self::OPERATION_COOLDOWN_DEFAULT_SECONDS;
    }

    private static function operation_has_runtime_cache_window(
        string $operation,
        string $method = '',
        bool $runtime_hook_changed = false,
        bool $runtime_prepend_cached = false
    ): bool {
        if ( HostingPlatform::is_locked_down_managed() ) {
            return false;
        }

        return $runtime_hook_changed
            || in_array( $method, [ self::METHOD_HTACCESS, self::METHOD_USER_INI, self::METHOD_HTACCESS_USER_INI ], true )
            || ( $operation === 'uninstall' && $runtime_prepend_cached );
    }

    private static function start_operation_cooldown(
        string $operation,
        string $method = '',
        bool $runtime_hook_changed = false,
        bool $runtime_prepend_cached = false
    ): void {
        $operation = in_array( $operation, [ 'install', 'uninstall' ], true ) ? $operation : 'install';
        $runtime_cache_window = self::operation_has_runtime_cache_window( $operation, $method, $runtime_hook_changed, $runtime_prepend_cached );
        $seconds = self::calculate_cooldown_seconds( $operation, $method, $runtime_hook_changed, $runtime_prepend_cached );
        if ( $seconds <= 0 ) {
            return;
        }

        $payload = [
            'operation'            => $operation,
            'method'               => sanitize_key( $method ),
            'seconds'              => $seconds,
            'started_at'           => time(),
            'runtime_cache_window' => $runtime_cache_window,
        ];

        self::set_runtime_transition_state( $payload );
    }

    private static function get_runtime_transition_guard(): array {
        $cooldown = self::get_operation_cooldown_state();
        if ( $cooldown['active'] ) {
            if ( self::current_cooldown_target_state_reached( $cooldown ) ) {
                if ( self::transition_target_can_clear( $cooldown ) ) {
                    self::clear_operation_cooldown();
                    return self::inactive_operation_cooldown_state();
                }
            } elseif ( self::transition_cache_wait_elapsed( $cooldown ) ) {
                self::clear_operation_cooldown();
                return self::inactive_operation_cooldown_state();
            } elseif ( self::transition_can_fail_open( $cooldown ) ) {
                self::clear_operation_cooldown();
                return self::inactive_operation_cooldown_state();
            }

            return $cooldown;
        }

        if ( HostingPlatform::is_locked_down_managed() ) {
            return self::inactive_operation_cooldown_state();
        }

        $bootstrap_path = self::get_bootstrap_path();
        if ( $bootstrap_path === '' || ! is_file( $bootstrap_path ) ) {
            return self::inactive_operation_cooldown_state();
        }

        $directive_exists_on_disk = self::has_managed_runtime_hook_on_disk();
        $seconds = max( self::OPERATION_RUNTIME_CACHE_SECONDS, self::get_user_ini_cache_ttl() );

        if (
            self::get_runtime_desired_enabled() === false
            && ! $directive_exists_on_disk
            && self::paths_match( (string) ini_get( 'auto_prepend_file' ), $bootstrap_path )
        ) {
            $recent_deactivation = self::recent_deactivation_cache_window( $seconds );
            if ( empty( $recent_deactivation['active'] ) ) {
                return self::inactive_operation_cooldown_state();
            }

            return [
                'active'               => true,
                'operation'            => 'uninstall',
                'method'               => self::METHOD_USER_INI,
                'seconds'              => $seconds,
                'seconds_remaining'    => (int) $recent_deactivation['seconds_remaining'],
                'runtime_cache_window' => true,
                'message'              => self::build_pending_deactivation_message( [ 'seconds' => $seconds ] ),
            ];
        }

        return self::inactive_operation_cooldown_state();
    }

    /** @return array{active: bool, seconds_remaining: int} */
    private static function recent_deactivation_cache_window( int $seconds ): array {
        $mutation = self::get_runtime_state_mutation();
        $updated_at = max( 0, (int) ( $mutation['updated_at'] ?? 0 ) );
        if (
            $seconds <= 0
            || $updated_at <= 0
            || ! empty( $mutation['enabled'] )
            || (string) ( $mutation['caller'] ?? '' ) !== 'uninstall'
            || empty( $mutation['persisted'] )
        ) {
            return [
                'active'            => false,
                'seconds_remaining' => 0,
            ];
        }

        $remaining = ( $updated_at + $seconds ) - time();
        if ( $remaining <= 0 ) {
            return [
                'active'            => false,
                'seconds_remaining' => 0,
            ];
        }

        return [
            'active'            => true,
            'seconds_remaining' => $remaining,
        ];
    }

    private static function current_cooldown_target_state_reached( array $cooldown ): bool {
        $bootstrap_path = self::get_bootstrap_path();
        $prepend_value = (string) ini_get( 'auto_prepend_file' );
        $is_locked_down_managed = HostingPlatform::is_locked_down_managed();
        $artifacts = self::runtime_artifact_state( $bootstrap_path );
        $runtime_enforceable = $artifacts['runtime_enforceable'];
        $directive_exists_on_disk = $artifacts['directive_exists_on_disk'];
        $runtime_points_to_bootstrap = self::paths_match( $prepend_value, $bootstrap_path );
        $runtime_matches_bootstrap = false;

        if ( self::should_probe_runtime_activation( $runtime_enforceable, $directive_exists_on_disk, $is_locked_down_managed, $runtime_points_to_bootstrap ) ) {
            $runtime_matches_bootstrap = self::probe_runtime_activation( $bootstrap_path, self::should_use_cached_activation_probe( $cooldown ) ) === true;
        }

        $stale_runtime_prepend = (
            ! $is_locked_down_managed
            && $runtime_points_to_bootstrap
            && ( ! $directive_exists_on_disk || ! $runtime_enforceable )
        );

        return self::cooldown_target_state_reached(
            $cooldown,
            $runtime_matches_bootstrap,
            $runtime_enforceable,
            MuPluginLoader::is_installed(),
            $directive_exists_on_disk,
            $artifacts['runtime_config_store_exists'],
            $stale_runtime_prepend,
            $prepend_value,
            $bootstrap_path
        );
    }

    private static function cooldown_target_state_reached(
        array $cooldown,
        bool $runtime_matches_bootstrap,
        bool $runtime_enforceable,
        bool $mu_plugin_installed,
        bool $directive_exists_on_disk,
        bool $runtime_config_store_exists,
        bool $stale_runtime_prepend,
        string $prepend_value,
        string $bootstrap_path
    ): bool {
        if ( empty( $cooldown['active'] ) ) {
            return false;
        }

        $operation = (string) ( $cooldown['operation'] ?? '' );
        if ( $operation === 'install' ) {
            if ( $runtime_matches_bootstrap ) {
                return true;
            }

            return empty( $cooldown['runtime_cache_window'] )
                && $runtime_enforceable
                && $mu_plugin_installed;
        }

        if ( $operation === 'uninstall' ) {
            return ! $runtime_matches_bootstrap
                && ! $runtime_enforceable
                && ! $mu_plugin_installed
                && ! $directive_exists_on_disk
                && ! $runtime_config_store_exists
                && ! $stale_runtime_prepend
                && ! self::paths_match( $prepend_value, $bootstrap_path );
        }

        return false;
    }

    private static function deactivation_cleanup_required_on_disk(): bool {
        $artifacts = self::runtime_artifact_state();

        return $artifacts['runtime_enforceable']
            || $artifacts['runtime_config_store_exists']
            || $artifacts['directive_exists_on_disk']
            || MuPluginLoader::is_installed();
    }

    private static function transition_target_can_clear( array $cooldown ): bool {
        $operation = (string) ( $cooldown['operation'] ?? '' );
        if ( $operation !== 'uninstall' ) {
            return true;
        }

        if ( empty( $cooldown['runtime_cache_window'] ) ) {
            return true;
        }

        return (int) ( $cooldown['seconds_remaining'] ?? 0 ) <= 0;
    }

    private static function transition_cache_wait_elapsed( array $cooldown ): bool {
        return (string) ( $cooldown['operation'] ?? '' ) === 'uninstall'
            && ! empty( $cooldown['runtime_cache_window'] )
            && (int) ( $cooldown['seconds_remaining'] ?? 0 ) <= 0;
    }

    private static function transition_can_fail_open( array $cooldown ): bool {
        $operation = (string) ( $cooldown['operation'] ?? '' );
        if ( $operation !== 'install' ) {
            return false;
        }

        return (int) ( $cooldown['seconds_remaining'] ?? 0 ) <= 0;
    }

    private static function inactive_operation_cooldown_state(): array {
        return [
            'active'               => false,
            'operation'            => '',
            'method'               => '',
            'seconds'              => 0,
            'seconds_remaining'    => 0,
            'runtime_cache_window' => false,
            'message'              => '',
        ];
    }

    private static function clear_operation_cooldown(): void {
        delete_option( self::RUNTIME_TRANSITION_OPTION );
        self::flush_runtime_option_cache( self::RUNTIME_TRANSITION_OPTION );
    }

    private static function get_operation_cooldown_state(): array {
        $inactive = self::inactive_operation_cooldown_state();
        $payload = self::get_runtime_transition_state();

        if ( empty( $payload ) ) {
            return $inactive;
        }

        $started_at = isset( $payload['started_at'] ) ? (int) $payload['started_at'] : 0;
        $seconds    = isset( $payload['seconds'] ) ? max( 0, (int) $payload['seconds'] ) : 0;
        $operation  = isset( $payload['operation'] ) && is_string( $payload['operation'] ) ? $payload['operation'] : 'install';
        $method     = isset( $payload['method'] ) && is_string( $payload['method'] ) ? sanitize_key( $payload['method'] ) : '';
        $runtime_cache_window = ! empty( $payload['runtime_cache_window'] );

        if ( $operation !== 'install' && $operation !== 'uninstall' ) {
            return $inactive;
        }

        if ( $started_at <= 0 || $seconds <= 0 ) {
            return $inactive;
        }

        $remaining = max( 0, ( $started_at + $seconds ) - time() );

        if ( $runtime_cache_window && $operation === 'uninstall' ) {
            $message = $remaining > 0
                ? self::build_pending_deactivation_message(
                    [
                        'active'               => true,
                        'runtime_cache_window' => true,
                        'seconds'              => $seconds,
                    ]
                )
                : 'The server-level Web Application Firewall (WAF) has been disabled. SiteFort is still verifying that the server has cleared its PHP startup configuration.';
        } elseif ( $runtime_cache_window ) {
            $message = self::build_pending_activation_message();
        } else {
            $message = $operation === 'uninstall'
                ? 'Removing Server-Level WAF.'
                : 'Activating Server-Level WAF.';
        }

        return [
            'active'               => true,
            'operation'            => $operation,
            'method'               => $method,
            'seconds'              => $seconds,
            'seconds_remaining'    => $remaining,
            'runtime_cache_window' => $runtime_cache_window,
            'message'              => $message,
        ];
    }

    private static function probe_runtime_activation_uncached( string $bootstrap_path ): ?bool {
        if ( ! function_exists( 'home_url' ) || ! function_exists( 'wp_remote_get' ) ) {
            return null;
        }

        $target_url = add_query_arg(
            [
                self::ACTIVATION_PROBE_QUERY => '1',
                'sitefort_probe' => (string) ( microtime( true ) . '-' . wp_rand( 1000, 9999 ) ),
            ],
            home_url( '/' )
        );

        $path  = (string) ( wp_parse_url( $target_url, PHP_URL_PATH ) ?: '/' );
        $query = (string) ( wp_parse_url( $target_url, PHP_URL_QUERY ) ?: '' );
        $timestamp = time();
        $nonce     = wp_generate_password( 20, false, false );
        $signature = \SiteFort\Includes\SiteFortKeyManager::build_server_verification_signature( 'GET', $path, $query, $nonce, $timestamp );
        if ( $signature === '' ) {
            return null;
        }

        $response = wp_remote_get(
            $target_url,
            [
                'timeout'             => 3,
                'redirection'         => 0,
                'reject_unsafe_urls'  => true,
                'limit_response_size' => 16,
                'headers'             => [
                    'Accept' => 'text/plain',
                    'Cache-Control' => 'no-cache',
                    'Pragma' => 'no-cache',
                    'X-SiteFort-Verify-Version' => '1',
                    'X-SiteFort-Verify-Timestamp' => (string) $timestamp,
                    'X-SiteFort-Verify-Nonce' => $nonce,
                    'X-SiteFort-Verify-Signature' => $signature,
                ],
            ]
        );

        if ( is_wp_error( $response ) ) {
            return null;
        }

        $headers = wp_remote_retrieve_headers( $response );
        $header_value = '';
        if ( is_object( $headers ) && method_exists( $headers, 'getAll' ) ) {
            $headers = $headers->getAll();
        }
        if ( is_array( $headers ) ) {
            foreach ( $headers as $name => $value ) {
                if ( ! is_string( $name ) || strtolower( $name ) !== self::ACTIVATION_PROBE_HEADER ) {
                    continue;
                }

                if ( is_array( $value ) ) {
                    $value = reset( $value );
                }

                $header_value = is_scalar( $value ) ? trim( (string) $value ) : '';
                break;
            }
        }

        $body = trim( (string) wp_remote_retrieve_body( $response ) );

        return $header_value === self::ACTIVATION_PROBE_VALUE && $body === self::ACTIVATION_PROBE_VALUE;
    }

    /**
     * Get the configured per-directory ini cache TTL for the current PHP runtime.
     */
    private static function get_user_ini_cache_ttl(): int {
        $ttl = ini_get( 'user_ini.cache_ttl' );
        if ( $ttl === false ) {
            return 0;
        }

        return max( 0, (int) $ttl );
    }

    /**
     * Quick check whether the extended WAF is installed and pointing to our bootstrap.
     *
     * @return bool
     */
    public static function is_installed(): bool {
        $artifacts = self::runtime_artifact_state();
        if ( ! $artifacts['bootstrap_exists'] || ! $artifacts['runtime_enforceable'] ) {
            return false;
        }

        $prepend_value = (string) ini_get( 'auto_prepend_file' );
        if ( $prepend_value === '' ) {
            return false;
        }

        return self::paths_match( $prepend_value, $artifacts['bootstrap_path'] );
    }

    /**
     * Whether runtime bootstrap/config files should be kept current.
     */
    public static function should_manage_runtime_assets(): bool {
        $artifacts = self::runtime_artifact_state();
        if ( ! $artifacts['bootstrap_exists'] || $artifacts['bootstrap_disabled_stub'] ) {
            return false;
        }

        $desired_enabled = self::get_runtime_desired_enabled();
        if ( $desired_enabled !== null ) {
            return $desired_enabled;
        }

        return $artifacts['directive_exists_on_disk'] && ( $artifacts['config_exists'] || $artifacts['runtime_config_store_exists'] );
    }

    /**
     * Whether SiteFort has a managed auto_prepend_file directive persisted on disk.
     */
    public static function has_managed_runtime_hook_on_disk(): bool {
        return self::user_ini_directive_exists_on_disk() || self::htaccess_directive_exists_on_disk();
    }

    private static function should_manage_mu_loader(): bool {
        $selected_layer = self::get_runtime_layer();
        if ( $selected_layer === self::LAYER_MU_PLUGIN ) {
            return true;
        }

        if ( in_array( $selected_layer, [ self::LAYER_AUTO_PREPEND, self::LAYER_NONE ], true ) ) {
            return false;
        }

        return MuPluginLoader::is_installed() && ! self::has_managed_runtime_hook_on_disk();
    }

    private static function should_defer_mu_loader_removal_until_auto_prepend_confirmed( string $bootstrap_path ): bool {
        if ( self::get_runtime_layer() !== self::LAYER_AUTO_PREPEND || self::get_runtime_desired_enabled() !== true ) {
            return false;
        }

        if ( ! self::has_managed_runtime_hook_on_disk() ) {
            return false;
        }

        return ! self::auto_prepend_runtime_confirmed( $bootstrap_path );
    }

    private static function auto_prepend_runtime_confirmed( string $bootstrap_path ): bool {
        $artifacts = self::runtime_artifact_state( $bootstrap_path );
        if ( ! $artifacts['bootstrap_exists'] || $artifacts['bootstrap_disabled_stub'] ) {
            return false;
        }

        if ( self::paths_match( (string) ini_get( 'auto_prepend_file' ), $artifacts['bootstrap_path'] ) ) {
            return true;
        }

        if ( ! $artifacts['runtime_enforceable'] || ! $artifacts['directive_exists_on_disk'] ) {
            return false;
        }

        return self::probe_runtime_activation( $artifacts['bootstrap_path'], false ) === true;
    }

    private static function bootstrap_is_disabled_stub( string $path ): bool {
        if ( $path === '' || ! is_file( $path ) ) {
            return false;
        }

        $contents = FilesystemMutation::read_file_contents( $path );
        return is_string( $contents ) && strpos( $contents, self::SAFE_BOOTSTRAP_MARKER ) !== false;
    }

    private static function runtime_config_enforces_policy( string $path ): bool {
        if ( $path === '' || ! is_file( $path ) || ! is_readable( $path ) ) {
            return false;
        }

        $config = @include $path;
        if ( ! is_array( $config ) ) {
            return false;
        }

        return self::runtime_config_payload_enforces_policy( $config );
    }

    /**
     * @param array<string,mixed> $config
     */
    private static function runtime_config_payload_enforces_policy( array $config ): bool {
        if ( (string) ( $config['origin_enforcement_mode'] ?? '' ) !== 'enforce' ) {
            return false;
        }

        $required_files = [
            (string) ( $config['engine_file'] ?? '' ),
            (string) ( $config['search_trust_core_file'] ?? '' ),
            (string) ( $config['search_trust_context_file'] ?? '' ),
            (string) ( $config['search_trust_dns_verifier_file'] ?? '' ),
            (string) ( $config['request_provenance_file'] ?? '' ),
        ];

        foreach ( $required_files as $required_file ) {
            if ( $required_file === '' || ! is_file( $required_file ) || ! is_readable( $required_file ) ) {
                return false;
            }
        }

        return true;
    }

    /**
     * @return array<string,mixed>|null
     */
    private static function runtime_store_config_payload(): ?array {
        $payload = WafRuntimeStore::get( WafRuntimeStore::KEY_BOOTSTRAP_CONFIG, null );

        return is_array( $payload ) ? $payload : null;
    }

    /**
     * @return array{
     *   bootstrap_path:string,
     *   bootstrap_exists:bool,
     *   config_exists:bool,
     *   bootstrap_disabled_stub:bool,
     *   runtime_config_store_exists:bool,
     *   runtime_enforceable:bool,
     *   user_ini_directive_exists:bool,
     *   directive_exists_on_disk:bool
     * }
     */
    private static function runtime_artifact_state( ?string $bootstrap_path = null ): array {
        $bootstrap_path = $bootstrap_path ?? self::get_bootstrap_path();
        $config_path = self::get_config_path();
        $bootstrap_exists = $bootstrap_path !== '' && is_file( $bootstrap_path );
        $config_exists = is_file( $config_path );
        $bootstrap_disabled_stub = $bootstrap_exists && self::bootstrap_is_disabled_stub( $bootstrap_path );
        $runtime_store_payload = self::runtime_store_config_payload();
        $runtime_config_store_exists = is_array( $runtime_store_payload );
        $file_runtime_enforceable = $bootstrap_exists
            && $config_exists
            && ! $bootstrap_disabled_stub
            && self::runtime_config_enforces_policy( $config_path );
        $runtime_store_config_enforceable = $bootstrap_exists
            && ! $bootstrap_disabled_stub
            && is_array( $runtime_store_payload )
            && self::runtime_config_payload_enforces_policy( $runtime_store_payload );
        $user_ini_directive_exists = self::user_ini_directive_exists_on_disk();
        $htaccess_directive_exists = self::htaccess_directive_exists_on_disk();

        return [
            'bootstrap_path' => $bootstrap_path,
            'bootstrap_exists' => $bootstrap_exists,
            'config_exists' => $config_exists,
            'bootstrap_disabled_stub' => $bootstrap_disabled_stub,
            'runtime_config_store_exists' => $runtime_config_store_exists,
            'runtime_enforceable' => $file_runtime_enforceable || $runtime_store_config_enforceable,
            'user_ini_directive_exists' => $user_ini_directive_exists,
            'directive_exists_on_disk' => $user_ini_directive_exists || $htaccess_directive_exists,
        ];
    }

    /**
     * @return array{success: bool, errors: array<int,string>}
     */
    private static function delete_runtime_config_payloads(): array {
        $errors = [];

        if ( ! WafRuntimeStore::delete( WafRuntimeStore::KEY_BOOTSTRAP_CONFIG ) ) {
            $errors[] = 'Could not remove the database-backed Web Application Firewall runtime configuration.';
        }

        return [
            'success' => empty( $errors ),
            'errors'  => $errors,
        ];
    }

    private static function get_runtime_desired_enabled(): ?bool {
        $value = self::read_runtime_option_value( self::RUNTIME_ENABLED_OPTION );
        if ( $value === null ) {
            return null;
        }

        return (string) $value === '1';
    }

    private static function persist_runtime_state( bool $enabled, string $layer, string $mutation_source ): bool {
        $enabled_persisted = self::set_runtime_desired_enabled( $enabled );
        $layer_persisted   = self::set_runtime_layer( $layer );
        $persisted = $enabled_persisted && $layer_persisted;
        self::record_runtime_state_mutation( $enabled, $layer, $persisted, $mutation_source );

        return $persisted;
    }

    private static function set_runtime_desired_enabled( bool $enabled ): bool {
        $value = $enabled ? '1' : '0';
        update_option( self::RUNTIME_ENABLED_OPTION, $value, false );
        self::flush_runtime_option_cache( self::RUNTIME_ENABLED_OPTION );

        return self::option_value_persisted( self::RUNTIME_ENABLED_OPTION, $value );
    }

    private static function get_runtime_layer(): ?string {
        $value = (string) ( self::read_runtime_option_value( self::RUNTIME_LAYER_OPTION ) ?? '' );
        if ( in_array( $value, [ self::LAYER_AUTO_PREPEND, self::LAYER_MU_PLUGIN, self::LAYER_NONE ], true ) ) {
            return $value;
        }

        return null;
    }

    private static function set_runtime_layer( string $layer ): bool {
        if ( ! in_array( $layer, [ self::LAYER_AUTO_PREPEND, self::LAYER_MU_PLUGIN, self::LAYER_NONE ], true ) ) {
            $layer = self::LAYER_NONE;
        }

        update_option( self::RUNTIME_LAYER_OPTION, $layer, false );
        self::flush_runtime_option_cache( self::RUNTIME_LAYER_OPTION );

        return self::option_value_persisted( self::RUNTIME_LAYER_OPTION, $layer );
    }

    private static function option_value_persisted( string $option_name, string $expected_value ): bool {
        $stored_value = self::read_runtime_option_value( $option_name );

        return $stored_value !== null && hash_equals( $expected_value, (string) $stored_value );
    }

    private static function read_runtime_option_value( string $option_name ): ?string {
        global $wpdb;

        if ( $wpdb instanceof \wpdb && ! empty( $wpdb->options ) ) {
            $options_table = self::runtime_options_table_identifier();
            if ( $options_table === null ) {
                return null;
            }

            // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared,PluginCheck.Security.DirectDB.UnescapedDBParameter
            $sql = $wpdb->prepare(
                "SELECT `option_value` FROM {$options_table} WHERE `option_name` = %s LIMIT 1",
                $option_name
            );
            // phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared,PluginCheck.Security.DirectDB.UnescapedDBParameter

            if ( ! is_string( $sql ) || $sql === '' ) {
                return null;
            }

            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.NotPrepared,PluginCheck.Security.DirectDB.UnescapedDBParameter -- WAF activation state must bypass persistent object-cache staleness on hosts with aggressive option caching; the table identifier is strictly validated by runtime_options_table_identifier().
            $stored_value = $wpdb->get_var( $sql );

            return $stored_value === null ? null : (string) $stored_value;
        }

        $value = get_option( $option_name, self::OPTION_MISSING );
        return $value === self::OPTION_MISSING ? null : (string) $value;
    }

    private static function runtime_options_table_identifier(): ?string {
        global $wpdb;

        $table_name = isset( $wpdb->options ) ? (string) $wpdb->options : '';
        if (
            $table_name === ''
            || strlen( $table_name ) > 64
            || preg_match( '/^[A-Za-z0-9_]+$/', $table_name ) !== 1
        ) {
            return null;
        }

        return '`' . esc_sql( $table_name ) . '`';
    }

    private static function flush_runtime_option_cache( string $option_name ): void {
        if ( function_exists( 'wp_cache_delete' ) ) {
            wp_cache_delete( $option_name, 'options' );
            wp_cache_delete( 'alloptions', 'options' );
            wp_cache_delete( 'notoptions', 'options' );
        }
    }

    /** @param array<string,mixed> $payload */
    private static function set_runtime_transition_state( array $payload ): void {
        $operation = sanitize_key( (string) ( $payload['operation'] ?? '' ) );
        if ( ! in_array( $operation, [ 'install', 'uninstall' ], true ) ) {
            return;
        }

        $state = [
            'operation'            => $operation,
            'method'               => sanitize_key( (string) ( $payload['method'] ?? '' ) ),
            'seconds'              => max( 0, (int) ( $payload['seconds'] ?? 0 ) ),
            'started_at'           => max( 0, (int) ( $payload['started_at'] ?? time() ) ),
            'runtime_cache_window' => ! empty( $payload['runtime_cache_window'] ),
        ];

        update_option( self::RUNTIME_TRANSITION_OPTION, $state, false );
        self::flush_runtime_option_cache( self::RUNTIME_TRANSITION_OPTION );
    }

    /**
     * @return array<string,mixed>
     */
    private static function get_runtime_transition_state(): array {
        $stored = self::read_runtime_option_value( self::RUNTIME_TRANSITION_OPTION );
        $raw = $stored === null ? [] : SafeUnserializer::maybe_unserialize_without_objects( $stored );
        if ( ! is_array( $raw ) ) {
            return [];
        }

        $operation = sanitize_key( (string) ( $raw['operation'] ?? '' ) );
        if ( ! in_array( $operation, [ 'install', 'uninstall' ], true ) ) {
            return [];
        }

        $started_at = max( 0, (int) ( $raw['started_at'] ?? 0 ) );
        $seconds    = max( 0, (int) ( $raw['seconds'] ?? 0 ) );
        if ( $started_at <= 0 || $seconds <= 0 ) {
            return [];
        }

        return [
            'operation'            => $operation,
            'method'               => sanitize_key( (string) ( $raw['method'] ?? '' ) ),
            'seconds'              => $seconds,
            'started_at'           => $started_at,
            'runtime_cache_window' => ! empty( $raw['runtime_cache_window'] ),
        ];
    }

    private static function record_runtime_state_mutation( bool $enabled, string $layer, bool $persisted, string $mutation_source ): void {
        $payload = [
            'enabled' => $enabled,
            'layer' => $layer,
            'persisted' => $persisted,
            'caller' => sanitize_key( $mutation_source ),
            'request_method' => sanitize_key( self::server_value( 'REQUEST_METHOD' ) ),
            'request_uri' => esc_url_raw( self::server_value( 'REQUEST_URI' ) ),
            'rest_route' => sanitize_text_field( self::server_value( 'REST_ROUTE' ) ),
            'updated_at' => time(),
        ];

        update_option( self::RUNTIME_MUTATION_OPTION, $payload, false );
        self::flush_runtime_option_cache( self::RUNTIME_MUTATION_OPTION );
    }

    private static function get_runtime_state_mutation(): array {
        $stored = self::read_runtime_option_value( self::RUNTIME_MUTATION_OPTION );
        $raw = $stored === null ? [] : SafeUnserializer::maybe_unserialize_without_objects( $stored );
        if ( ! is_array( $raw ) ) {
            return [];
        }

        return [
            'enabled' => ! empty( $raw['enabled'] ),
            'layer' => sanitize_key( (string) ( $raw['layer'] ?? '' ) ),
            'persisted' => ! empty( $raw['persisted'] ),
            'caller' => sanitize_text_field( (string) ( $raw['caller'] ?? '' ) ),
            'request_method' => sanitize_key( (string) ( $raw['request_method'] ?? '' ) ),
            'request_uri' => esc_url_raw( (string) ( $raw['request_uri'] ?? '' ) ),
            'rest_route' => sanitize_text_field( (string) ( $raw['rest_route'] ?? '' ) ),
            'updated_at' => max( 0, (int) ( $raw['updated_at'] ?? 0 ) ),
        ];
    }

    // ---------------------------------------------------------------
    // Path helpers
    // ---------------------------------------------------------------

    /**
     * @return string Absolute path to the data directory.
     */
    public static function get_data_dir(): string {
        return WP_CONTENT_DIR . '/' . self::DATA_DIR_NAME;
    }

    /**
     * @return string Absolute path to the WAF config file.
     */
    public static function get_config_path(): string {
        return self::get_data_dir() . '/' . self::CONFIG_FILE;
    }

    /**
     * @return string Absolute path to the .htaccess file.
     */
    private static function get_htaccess_path(): string {
        return SitePathResolver::get_home_filesystem_path() . '.htaccess';
    }

    private static function get_user_ini_path(): string {
        $filename = self::get_user_ini_filename();
        return $filename !== '' ? SitePathResolver::get_home_filesystem_path() . $filename : '';
    }

    private static function get_user_ini_filename(): string {
        $filename = SitePathResolver::get_user_ini_filename();
        if ( $filename !== '' ) {
            return $filename;
        }

        return HostingPlatform::is_locked_down_managed() ? self::DEFAULT_USER_INI_FILE : '';
    }

    private static function get_user_ini_label(): string {
        $filename = self::get_user_ini_filename();
        return $filename !== '' ? $filename : 'the per-directory PHP config file';
    }

    private static function paths_match( string $left, string $right ): bool {
        if ( $left === '' || $right === '' ) {
            return false;
        }

        $left_real  = realpath( $left );
        $right_real = realpath( $right );

        return is_string( $left_real ) && is_string( $right_real ) && $left_real === $right_real;
    }

    private static function paths_match_or_same( string $left, string $right ): bool {
        if ( $left === '' || $right === '' ) {
            return false;
        }

        if ( $left === $right ) {
            return true;
        }

        return self::paths_match( $left, $right );
    }

    private static function ensure_data_dir(): bool {
        return DataDirectoryProtection::ensure_runtime_root();
    }

    private static function ensure_runtime_directory( string $directory ): bool {
        if ( self::is_data_dir_path( $directory ) ) {
            return self::ensure_data_dir();
        }

        return FilesystemMutation::ensure_directory( $directory );
    }

    private static function is_data_dir_path( string $directory ): bool {
        $directory = self::normalize_runtime_path( $directory );
        $data_dir  = self::normalize_runtime_path( self::get_data_dir() );

        return $directory === $data_dir || self::paths_match( $directory, $data_dir );
    }

    private static function normalize_runtime_path( string $path ): string {
        return rtrim( wp_normalize_path( $path ), '/' );
    }

    /**
     * Copy the bootstrap atomically.
     *
     * @return true|string
     */
    private static function copy_bootstrap_file( string $source, string $destination, string $chained_prepend_path = '' ) {
        $directory = dirname( $destination );
        if ( ! self::ensure_runtime_directory( $directory ) ) {
            return 'SiteFort could not access the Web Application Firewall data directory.';
        }

        if ( ! is_file( $source ) || ! is_readable( $source ) ) {
            return 'SiteFort could not read the Web Application Firewall bootstrap source.';
        }

        $contents = FilesystemMutation::read_file_contents( $source );
        if ( ! is_string( $contents ) ) {
            return 'SiteFort could not read the Web Application Firewall bootstrap source.';
        }

        $contents = self::build_bootstrap_contents( $contents, $chained_prepend_path, $destination );
        $mode     = defined( 'FS_CHMOD_FILE' ) ? (int) FS_CHMOD_FILE : 0644;
        $temp     = $destination . '.tmp.' . FilesystemMutation::temporary_suffix();

        if ( ! FilesystemMutation::write_bytes_to_file( $temp, $contents, $mode ) ) {
            return 'SiteFort could not create a temporary Web Application Firewall bootstrap file.';
        }

        if ( ! FilesystemMutation::move_path( $temp, $destination ) ) {
            FilesystemMutation::delete_path( $temp );
            return 'SiteFort could not replace the Web Application Firewall bootstrap file safely.';
        }

        if ( ! FilesystemMutation::verify_written_contents( $destination, $contents ) ) {
            return 'Bootstrap was written but on-disk contents did not match the expected payload.';
        }

        return true;
    }

    /**
     * Keep auto_prepend_file targets valid after uninstall.
     */
    private static function write_safe_bootstrap_stub( string $destination, string $chained_prepend_path = '' ): bool {
        $directory = dirname( $destination );
        if ( ! self::ensure_runtime_directory( $directory ) ) {
            return false;
        }

        $chained_prepend_path = self::normalize_chainable_prepend_path( $chained_prepend_path, $destination );

        $contents  = "<?php\n";
        $contents .= "// SiteFort WAF disabled safety bootstrap.\n";
        $contents .= "if ( ! defined( '" . self::SAFE_BOOTSTRAP_MARKER . "' ) ) {\n";
        $contents .= "    define( '" . self::SAFE_BOOTSTRAP_MARKER . "', true );\n";
        $contents .= "}\n";

        if ( $chained_prepend_path !== '' ) {
            // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_var_export -- Stub source is generated PHP and needs a valid quoted path literal.
            $contents .= '$sitefort_previous_auto_prepend = ' . var_export( $chained_prepend_path, true ) . ";\n";
            $contents .= "if ( is_file( \$sitefort_previous_auto_prepend ) ) {\n";
            $contents .= "    include_once \$sitefort_previous_auto_prepend;\n";
            $contents .= "}\n";
            $contents .= "unset( \$sitefort_previous_auto_prepend );\n";
        }

        $contents .= "return;\n";

        $temp = $destination . '.tmp.stub.' . FilesystemMutation::temporary_suffix();
        if ( ! FilesystemMutation::write_bytes_to_file( $temp, $contents, defined( 'FS_CHMOD_FILE' ) ? (int) FS_CHMOD_FILE : 0644 ) ) {
            return false;
        }

        if ( ! FilesystemMutation::move_path( $temp, $destination ) ) {
            FilesystemMutation::delete_path( $temp );
            return false;
        }

        return FilesystemMutation::verify_written_contents( $destination, $contents );
    }

    private static function build_bootstrap_contents( string $contents, string $chained_prepend_path, string $destination ): string {
        $snippets = [];
        $runtime_storage_file = __DIR__ . '/BootstrapRuntimeStorage.php';
        if ( is_file( $runtime_storage_file ) ) {
            $snippets[] = 'if ( ! defined( \'SITEFORT_WAF_RUNTIME_STORAGE_FILE\' ) ) {' . "\n" .
                // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_var_export -- Bootstrap source is generated PHP and needs a valid quoted path literal.
                '    define( \'SITEFORT_WAF_RUNTIME_STORAGE_FILE\', ' . var_export( $runtime_storage_file, true ) . ' );' . "\n" .
                '}';
        }

        // Stamp the canonical data directory so the bootstrap reads config
        // from the right location when SITEFORT_WAF_BOOTSTRAP_PATH is used.
        $data_dir = self::get_data_dir();
        $snippets[] = 'if ( ! defined( \'SITEFORT_WAF_DATA_DIR\' ) ) {' . "\n" .
            // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_var_export -- Bootstrap source is generated PHP and needs a valid quoted path literal.
            '    define( \'SITEFORT_WAF_DATA_DIR\', ' . var_export( $data_dir, true ) . ' );' . "\n" .
            '}';

        $chained_prepend_path = self::normalize_chainable_prepend_path( $chained_prepend_path, $destination );
        if ( $chained_prepend_path !== '' ) {
            $snippets[] =
                // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_var_export -- Bootstrap source is generated PHP and needs a valid quoted path literal.
                '$sitefort_previous_auto_prepend = ' . var_export( $chained_prepend_path, true ) . ";\n" .
                'if ( is_file( $sitefort_previous_auto_prepend ) ) {' . "\n" .
                '    include_once $sitefort_previous_auto_prepend;' . "\n" .
                "}\n" .
                'unset( $sitefort_previous_auto_prepend );';
        }

        if ( $snippets === [] ) {
            return $contents;
        }

        $snippet = "\n" . implode( "\n", $snippets ) . "\n";

        $insert_after_guard = "/(define\\(\\s*'SITEFORT_WAF_LOADED'\\s*,\\s*true\\s*\\);\\s*)/";
        $updated = preg_replace( $insert_after_guard, '$1' . $snippet, $contents, 1 );

        return is_string( $updated ) ? $updated : $contents;
    }

    private static function mark_bootstrap_version(): void {
        if ( defined( 'SITEFORT_VERSION' ) ) {
            update_option( self::BOOTSTRAP_VERSION_OPTION, (string) SITEFORT_VERSION, false );
        }
    }

    // ---------------------------------------------------------------
    // .htaccess management
    // ---------------------------------------------------------------

    /**
     * Add the auto_prepend_file directive to .htaccess between SiteFort markers.
     *
     * @param string $bootstrap_path Absolute path to the deployed bootstrap file.
     * @param string $server_type    Detected server type for handler-scoped directives.
     * @return true|string True on success, error message on failure.
     */
    private static function install_htaccess( string $bootstrap_path, string $server_type ) {
        return self::write_htaccess_waf_section( $bootstrap_path, $server_type );
    }

    private static function install_htaccess_user_ini_protection() {
        return self::write_htaccess_waf_section( '', '' );
    }

    private static function write_htaccess_waf_section( string $bootstrap_path, string $server_type ) {
        $htaccess = self::get_htaccess_path();
        $contents = '';

        if ( is_file( $htaccess ) ) {
            $contents = FilesystemMutation::read_file_contents( $htaccess );
            if ( $contents === false ) {
                return 'Could not read .htaccess file.';
            }

            // Remove any existing SiteFort WAF section first.
            $contents = self::strip_htaccess_section( $contents );
        }

        $directives = [];

        if ( $bootstrap_path !== '' ) {
            $auto_prepend_rules = self::build_htaccess_auto_prepend_rules( $bootstrap_path, $server_type );
            if ( $auto_prepend_rules === '' ) {
                return 'Unsupported .htaccess WAF server type: ' . $server_type;
            }

            $directives[] = rtrim( $auto_prepend_rules, "\n" );
        }

        $user_ini_protection = self::build_user_ini_htaccess_deny_rules();
        if ( $user_ini_protection !== '' ) {
            $directives[] = rtrim( $user_ini_protection, "\n" );
        }

        if ( $directives === [] ) {
            return true;
        }

        $directive  = self::HTACCESS_BEGIN . "\n";
        $directive .= implode( "\n", $directives ) . "\n";
        $directive .= self::HTACCESS_END . "\n";

        $new_contents = trim( $contents ) !== '' ? rtrim( $contents ) . "\n\n" . $directive : $directive;

        $mode = is_file( $htaccess ) ? self::file_mode( $htaccess ) : null;
        $result = FilesystemMutation::rewrite_existing_file( $htaccess, $new_contents, $mode, true );
        if ( is_wp_error( $result ) ) {
            return 'Could not write to .htaccess file.';
        }

        return true;
    }

    private static function build_htaccess_auto_prepend_rules( string $bootstrap_path, string $server_type ): string {
        $escaped_path = addcslashes( $bootstrap_path, '"' );

        if ( $server_type === 'apache_mod' ) {
            $rules = '';
            foreach ( self::APACHE_MOD_PHP_IFMODULES as $module ) {
                $rules .= '<IfModule ' . $module . '>' . "\n" .
                    '    php_value auto_prepend_file "' . $escaped_path . '"' . "\n" .
                    '</IfModule>' . "\n";
            }

            return $rules;
        }

        if ( $server_type === 'litespeed' ) {
            return '<IfModule LiteSpeed>' . "\n" .
                '    php_value auto_prepend_file "' . $escaped_path . '"' . "\n" .
                '</IfModule>' . "\n" .
                '<IfModule lsapi_module>' . "\n" .
                '    php_value auto_prepend_file "' . $escaped_path . '"' . "\n" .
                '</IfModule>' . "\n";
        }

        return '';
    }

    private static function build_user_ini_htaccess_deny_rules(): string {
        $filename = self::get_user_ini_filename();
        if ( $filename === '' ) {
            return '';
        }

        return sprintf(
            '<Files "%s">' . "\n" .
            '<IfModule mod_authz_core.c>' . "\n" .
            '    Require all denied' . "\n" .
            '</IfModule>' . "\n" .
            '<IfModule mod_litespeed.c>' . "\n" .
            '    Order Deny,Allow' . "\n" .
            '    Deny from all' . "\n" .
            '</IfModule>' . "\n" .
            '<IfModule !mod_authz_core.c>' . "\n" .
            '    <IfModule !mod_litespeed.c>' . "\n" .
            '        Order Deny,Allow' . "\n" .
            '        Deny from all' . "\n" .
            '    </IfModule>' . "\n" .
            '</IfModule>' . "\n" .
            '</Files>' . "\n",
            addcslashes( $filename, '"' )
        );
    }

    /**
     * Remove the SiteFort WAF section from .htaccess contents.
     *
     * @param string $contents Current .htaccess content.
     * @return string Cleaned content.
     */
    private static function strip_htaccess_section( string $contents ): string {
        $pattern = self::managed_block_pattern( self::HTACCESS_BEGIN, self::HTACCESS_END );
        return preg_replace( $pattern, '', $contents ) ?? $contents;
    }

    /**
     * Remove the SiteFort WAF section from the .htaccess file on disk.
     *
     * @param string $htaccess Absolute path to .htaccess.
     * @return string|true 'removed' if a managed block was stripped, 'not_present' if no
     *                     SiteFort-managed content was found, or an error message string on failure.
     */
    private static function remove_htaccess_section( string $htaccess ) {
        $contents = FilesystemMutation::read_file_contents( $htaccess );
        if ( $contents === false ) {
            return 'Could not read .htaccess file.';
        }

        $cleaned = self::strip_htaccess_section( $contents );

        if ( $cleaned === $contents ) {
            return 'not_present';
        }

        $cleaned = ltrim( $cleaned, "\n\r" );
        $result = FilesystemMutation::rewrite_existing_file( $htaccess, $cleaned, self::file_mode( $htaccess ), true );
        if ( is_wp_error( $result ) ) {
            return 'Could not write to .htaccess file.';
        }

        return 'removed';
    }

    // ---------------------------------------------------------------
    // Per-directory PHP config management
    // ---------------------------------------------------------------

    /**
     * Write the auto_prepend_file directive into the active per-directory PHP config file.
     *
     * @param string $bootstrap_path Absolute path to the deployed bootstrap file.
     * @return true|string True on success, error message on failure.
     */
    private static function install_user_ini( string $bootstrap_path ) {
        $user_ini = self::get_user_ini_path();
        $label    = self::get_user_ini_label();
        $contents  = '';

        if ( $user_ini === '' ) {
            return 'Per-directory PHP configuration is disabled or uses an unsafe filename. Add auto_prepend_file = "' . $bootstrap_path . '" manually in php.ini or the host control panel.';
        }

        if ( is_file( $user_ini ) ) {
            $contents = FilesystemMutation::read_file_contents( $user_ini );
            if ( $contents === false ) {
                return 'Could not read ' . $label . ' file.';
            }

            // Remove only SiteFort-managed directives.
            $contents = self::strip_user_ini_directive( $contents );
        }

        $directive  = self::USER_INI_BEGIN . "\n";
        $directive .= 'auto_prepend_file = "' . $bootstrap_path . '"' . "\n";
        $directive .= self::USER_INI_END . "\n";

        $contents = self::comment_out_user_ini_prepend_directives( $contents );
        $new_contents = $directive . "\n" . ltrim( $contents );

        $mode = is_file( $user_ini ) ? self::file_mode( $user_ini ) : null;
        $result = FilesystemMutation::rewrite_existing_file( $user_ini, $new_contents, $mode, true );
        if ( is_wp_error( $result ) ) {
            return 'Could not write to ' . $label . ' file.';
        }

        return true;
    }

    /**
     * Remove auto_prepend_file lines from per-directory ini content.
     *
     * @param string $contents Current per-directory ini content.
     * @return string Cleaned content.
     */
    private static function strip_user_ini_directive( string $contents ): string {
        $pattern = self::managed_block_pattern( self::USER_INI_BEGIN, self::USER_INI_END );
        return preg_replace( $pattern, '', $contents ) ?? $contents;
    }

    private const USER_INI_FOREIGN_TAG = '; SITEFORT-DISABLED ';

    private static function comment_out_user_ini_prepend_directives( string $contents ): string {
        $tag = self::USER_INI_FOREIGN_TAG;
        return preg_replace_callback(
            '/^([ \t]*)(auto_prepend_file[ \t]*=.*)$/mi',
            static function ( array $matches ) use ( $tag ): string {
                return (string) $matches[1] . $tag . (string) $matches[2];
            },
            $contents
        ) ?? $contents;
    }

    /**
     * Restore foreign auto_prepend_file lines that install_user_ini() commented out
     * with the SITEFORT-DISABLED tag. Lines without the tag are left untouched.
     */
    private static function uncomment_user_ini_prepend_directives( string $contents ): string {
        $tag_pattern = preg_quote( self::USER_INI_FOREIGN_TAG, '/' );
        return preg_replace(
            '/^([ \t]*)' . $tag_pattern . '(auto_prepend_file[ \t]*=.*)$/mi',
            '$1$2',
            $contents
        ) ?? $contents;
    }

    /**
     * Build a regex that matches a SiteFort-managed config block.
     */
    private static function managed_block_pattern( string $begin, string $end ): string {
        return '/' . preg_quote( $begin, '/' ) . '.*?' . preg_quote( $end, '/' ) . '\s*/s';
    }

    /**
     * Remove the SiteFort-managed auto_prepend_file directive from a per-directory PHP config
     * file and restore any foreign auto_prepend_file lines we commented out at install time.
     *
     * @param string $user_ini Absolute path to the per-directory ini file.
     * @return string 'removed' if SiteFort-managed content was stripped (or restored), 'not_present'
     *                if no SiteFort traces were found, or an error message string on failure.
     */
    private static function remove_user_ini_directive( string $user_ini ) {
        $contents = FilesystemMutation::read_file_contents( $user_ini );
        if ( $contents === false ) {
            return 'Could not read ' . basename( $user_ini ) . ' file.';
        }

        $stripped  = self::strip_user_ini_directive( $contents );
        $restored  = self::uncomment_user_ini_prepend_directives( $stripped );
        $had_block = ( $stripped !== $contents );
        $had_foreign_restore = ( $restored !== $stripped );

        if ( ! $had_block && ! $had_foreign_restore ) {
            return 'not_present';
        }

        $restored = ltrim( $restored, "\n\r" );
        $result = FilesystemMutation::rewrite_existing_file( $user_ini, $restored, self::file_mode( $user_ini ), true );
        if ( is_wp_error( $result ) ) {
            return 'Could not write to ' . basename( $user_ini ) . ' file.';
        }

        return 'removed';
    }

    /**
     * Extract an auto_prepend_file value from per-directory ini content.
     */
    private static function extract_user_ini_prepend_path( string $contents ): string {
        if ( preg_match( '/^\s*auto_prepend_file\s*=\s*"?([^"\r\n;]+)"?\s*$/mi', $contents, $matches ) !== 1 ) {
            return '';
        }

        return trim( (string) $matches[1] );
    }

    /**
     * Extract an auto_prepend_file value from .htaccess content.
     */
    private static function extract_htaccess_prepend_path( string $contents ): string {
        if ( preg_match( '/^\s*php_value\s+auto_prepend_file\s+"?([^"\r\n]+)"?\s*$/mi', $contents, $matches ) !== 1 ) {
            return '';
        }

        return trim( (string) $matches[1] );
    }

    // ---------------------------------------------------------------
    // Data directory protection
    // ---------------------------------------------------------------

    /**
     * Write protective files (index.php and .htaccess) into the data directory.
     *
     * @param string $data_dir Absolute path to the data directory.
     */
    private static function protect_data_dir( string $data_dir ): void {
        DataDirectoryProtection::ensure_local_protection( $data_dir );
    }

    private static function can_directly_rewrite_runtime_file( string $path ): bool {
        if ( $path === '' ) {
            return true;
        }

        if ( is_file( $path ) ) {
            return wp_is_writable( $path ) || wp_is_writable( dirname( $path ) );
        }

        return wp_is_writable( dirname( $path ) );
    }

    private static function file_mode( string $path ): ?int {
        $perms = @fileperms( $path );
        return is_int( $perms ) ? ( $perms & 0777 ) : null;
    }
}
