<?php
defined( 'ABSPATH' ) or die();

require_once rsssl_path . 'lib/admin/class-encryption.php';

use RSSSL\lib\admin\Encryption;
use RSSSL\Pro\Security\WordPress\Firewall\Models\Rsssl_404_Block;
use RSSSL\Security\RSSSL_Htaccess_File_Manager;
use RSSSL\Security\WordPress\Two_Fa\Rsssl_Two_Fa_Status;
use RSSSL\Security\WordPress\Two_Fa\Repositories\Rsssl_Two_Fa_User_Repository;
use RSSSL\Security\WordPress\Two_Fa\Services\Rsssl_Two_Fa_Reminder_Service;
use RSSSL\Security\WordPress\Two_Fa\Models\Rsssl_Two_FA_Data_Parameters;

/**
 * WP-CLI integration for Really Simple Security
 *
 * For an overview of commands use wp help rsssl
 *
 * Usage examples:
 * wp rsssl activate_ssl
 * wp rsssl deactivate_ssl
 * wp rsssl activate_recommended_features
 * wp rsssl deactivate_recommended_features
 * wp rsssl activate_security_headers
 * wp rsssl deactivate_security_headers
 * wp rsssl update_option --name=site_has_ssl --value=true
 *
 * Booleans should be passed to update_option as 0 or 1.
 *
 * To complete all standard dashboard notices (recommended features + .htaccess redirect + HSTS + e-mail verification):
 *
 * wp rsssl activate_recommended_features
 * wp rsssl update_option --name=redirect --value=htaccess
 * wp rsssl update_option --name=hsts --value=1
 * wp rsssl update_option --name=hsts_preload --value=1
 * wp rsssl update_option --name=hsts_subdomains --value=1
 * wp rsssl update_option --name=hsts_max_age --value='63072000'
 * wp rsssl update_option --name=notifications_email_address --value='you@example.com'
 * wp option update rsssl_email_verification_status 'completed'
 */
class rsssl_wp_cli {

	use Encryption;

	public function __construct() {
		if ( $this->wp_cli_active() ) {
			add_action( 'init', [ $this, 'register_wp_cli_commands' ], 0 );
		}
	}

	/**
	 * Checks if the conditions for running a Pro WP-CLI command are met.
	 * This is called *within* the command handler, ensuring plugin is loaded.
	 * Outputs an error and exits if conditions are not met.
	 *
	 * @return bool True if conditions are met, false otherwise (though it usually exits on false).
	 */
	private function check_pro_command_preconditions(bool $skip_license = false ): bool {
		// Skip license check for free (non-pro) commands
		$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2);
		$command = $backtrace[1]['function'] ?? '';
		$command_list = $this->get_command_list();
		if ( isset($command_list[$command]) && $command_list[$command]['pro'] === false ) {
			return true;
		}
		// Check if Pro is active (redundant check, but safe)
		if ( ! defined( 'rsssl_pro' ) ) {
			WP_CLI::error(
				__( 'This command is related to functionality available in Really Simple Security Pro, please consider upgrading to unlock all powerful security features. Read more: https://really-simple-ssl.com/pro', 'really-simple-ssl' ),
				true // Exit after error
			);
			return false; // Should not be reached
		}

		if ( $skip_license ) {
			return true; // Skip license check if explicitly requested
		}
		// Check if license is valid (now safe to call)
		if ( ! RSSSL()->licensing->license_is_valid() ) {
			$activate_command = 'wp rsssl activate_license <YOUR_LICENSE_KEY>';
			// Check if the command exists in the list just to be safe
			if (!isset($this->get_command_list()['activate_license'])) {
				$activate_command = 'activate_license'; // Fallback text
			}
			WP_CLI::error(
				sprintf(
					__( 'It seems that no valid license key is activated for this domain. Activate your license key using the `%s` command, or purchase a valid license key via https://really-simple-ssl.com/pro', 'really-simple-ssl' ),
					$activate_command
				),
				true // Exit after error
			);
			return false; // Should not be reached
		}

		// All checks passed
		return true;
	}

	/**
	 * Check if WP-CLI is active.
	 *
	 * @return bool True if WP-CLI is active, false otherwise.
	 */
	public function wp_cli_active() {
		return defined( 'WP_CLI' ) && WP_CLI;
	}

	/**
	 * Activate SSL through WP-CLI.
	 *
	 * Provides options for verbose output, forcing activation despite warnings,
	 * skipping confirmation, and performing a dry run.
	 *
	 * ## OPTIONS
	 *
	 * [--verbose]
	 * : Show detailed steps during activation.
	 *
	 * [--force]
	 * : Force activation even if pre-flight checks issue warnings and skip confirmation prompt.
	 *
	 * [--yes]
	 * : Skip the confirmation prompt before activating.
	 *
	 * [--dry-run]
	 * : Perform checks and report intended actions without making changes.
	 *
	 * ## EXAMPLES
	 *
	 *     wp rsssl activate_ssl
	 *     wp rsssl activate_ssl --verbose --yes
	 *     wp rsssl activate_ssl --dry-run
	 *
	 * @param array $args Positional arguments (none used here).
	 * @param array $assoc_args Associative arguments (--verbose, --force, --yes, --dry-run).
	 * @return void
	 */
	public function activate_ssl( $args, $assoc_args ) {
		if ( ! $this->check_pro_command_preconditions() ) return;
		$is_verbose = WP_CLI\Utils\get_flag_value( $assoc_args, 'verbose', false );
		$is_force   = WP_CLI\Utils\get_flag_value( $assoc_args, 'force', false );
		$skip_confirm = WP_CLI\Utils\get_flag_value( $assoc_args, 'yes', false );
		$is_dry_run = WP_CLI\Utils\get_flag_value( $assoc_args, 'dry-run', false );

		if ( $is_dry_run ) {
			WP_CLI::line( "-- Dry Run Enabled: No changes will be made. --" );
		}

		try {
			// --- Suggestion 3: Pre-flight Checks ---
			if ( $is_verbose || $is_dry_run ) WP_CLI::debug( 'Running pre-activation checks...', 'rsssl-cli' );

			// Assume this function now exists and returns ['success' => bool, 'message' => string, 'warnings' => array]
			$checks = $this->perform_pre_flight_checks();

			if ( ! empty( $checks['warnings'] ) ) {
				foreach ( $checks['warnings'] as $warning ) {
					WP_CLI::warning( $warning );
				}
				if ( ! $is_force && ! $is_dry_run ) {
					WP_CLI::error( 'Pre-flight checks issued warnings. Use --force to proceed anyway.', false ); // Use false to allow dry-run continue
					if (!$is_dry_run) return; // Stop if not dry run
				}
			}

			if ( ! $checks['success'] ) {
				 // If checks outright fail (not just warnings)
				 WP_CLI::error( 'Pre-flight checks failed: ' . $checks['message'] );
				 return;
			}

			if ( $is_verbose || $is_dry_run ) WP_CLI::debug( 'Pre-flight checks passed.', 'rsssl-cli' );


			// --- Report Intended Actions (Dry Run) ---
			if ( $is_dry_run ) {
				 WP_CLI::line( "Intended actions:" );
				 WP_CLI::line( "- Update WordPress Site URL and Home URL to HTTPS." );
				 WP_CLI::line( "- Configure redirects (method depends on settings)." );
				 WP_CLI::line( "- Update internal links/content (if mixed content fixer enabled)." );
				 WP_CLI::line( "- Dismiss onboarding notice." );
				 WP_CLI::success( "Dry run complete. No changes were made." );
				 return; // End dry run here
			}


			// --- Suggestion 4: Confirmation Prompt ---
			// Skip confirmation if --yes or --force is used
			if ( ! $skip_confirm && ! $is_force ) {
				WP_CLI::confirm( 'Are you sure you want to activate SSL for this site?' );
				// WP_CLI::confirm exits script if user doesn't confirm
			}

			// --- Core Activation Logic ---
			if ( $is_verbose ) WP_CLI::debug( 'Attempting SSL activation...', 'rsssl-cli' );

			// --- Suggestion 5: Clarify Side Effects ---
			// Move onboarding dismissal inside the main activation logic or make it explicit
			// update_option( 'rsssl_onboarding_dismissed', true, false ); // Optionally moved inside activate_ssl or reported

			// --- Suggestion 1: Granular Failure Reasons ---
			// Assume RSSSL()->admin->activate_ssl() now returns an array or throws specific exceptions
			// Passing $is_verbose allows the underlying function to potentially output debug info too
			$result = RSSSL()->admin->activate_ssl( $is_verbose );

			// Check if $result is structured like ['success' => bool, 'message' => string]
			if ( is_array( $result ) && isset( $result['success'] ) ) {
				if ( $result['success'] ) {
					$success_message = 'SSL activated successfully.';
					// Suggestion 5: Clarify Side Effects (Example)
					 if ( get_option('rsssl_onboarding_dismissed') ) {
						 $success_message .= ' Onboarding notice dismissed.';
					 }
					WP_CLI::success( $success_message );
				} else {
					// Use the detailed message from the function
					WP_CLI::error( 'SSL activation failed: ' . ( $result['message'] ?? 'Unknown reason.' ) );
				}
			} else if ( $result === true ) { // Handle simple boolean success
				 WP_CLI::success( 'SSL activated successfully. Onboarding notice dismissed.' );
			} else { // Handle simple boolean failure or unexpected return
				 WP_CLI::error( 'SSL activation failed (unknown reason).' );
			}


		} catch ( Exception $e ) { // Catch specific exceptions if activate_ssl throws them
			// Suggestion 1 & 2: More specific error based on exception type if possible
			WP_CLI::error( 'Failed to activate SSL due to an unexpected error: ' . $e->getMessage() );
		}
	}

	/**
	 * Deactivate SSL through WP-CLI.
	 *
	 * @return void
	 */
	public function deactivate_ssl() {
		if ( ! $this->check_pro_command_preconditions() ) return;
		try {
			RSSSL()->admin->deactivate();
			WP_CLI::success( 'SSL deactivated' );
		} catch ( Exception $e ) {
			WP_CLI::error( 'Failed to deactivate SSL: ' . $e->getMessage() );
		}
	}

	/**
	 * Update a Really Simple Security option via WP-CLI.
	 * Booleans should be passed as 0 or 1.
	 *
	 * @param array $args Command-line positional arguments.
	 * @param array $assoc_args Command-line associative arguments.
	 *
	 * @return void
	 */
	public function update_option( $args, $assoc_args ) {
		if ( ! isset( $assoc_args['name'] ) || ! isset( $assoc_args['value'] ) ) {
			WP_CLI::error( 'Both --name and --value parameters are required.' );
		}

		$name  = sanitize_title( $assoc_args['name'] );
		$value = $assoc_args['value'];

		try {
			rsssl_update_option( $name, $value );
			WP_CLI::success( "Option $name updated to $value" );
		} catch ( Exception $e ) {
			WP_CLI::error( 'Failed to update option: ' . $e->getMessage() );
		}
	}

	/**
	 * Activate all recommended features via CLI
	 *
	 * @throws Exception
	 * return void
	 */
	public function activate_recommended_features() {
		if ( ! $this->check_pro_command_preconditions() ) return;
		try {
			RSSSL()->admin->activate_recommended_features();
		} catch ( Exception $e ) {
			WP_CLI::error( 'Failed to activate recommended features. ' . $e->getMessage() );
		}

		WP_CLI::success( 'Recommended features activated.' );
	}

	/**
	 * Deactivate all recommended features via CLI
	 *
	 * return void
	 */
	public function deactivate_recommended_features() {
		if ( ! $this->check_pro_command_preconditions() ) return;
		try {
			// Deactivate Vulnerability Scanner
			rsssl_update_option( 'enable_vulnerability_scanner', false );

			// Deactivate essential WordPress hardening features
            if (isset(RSSSL()->settingsConfigService)) {
                $recommended_hardening_fields = RSSSL()->settingsConfigService->getRecommendedHardeningSettings();
                foreach ( $recommended_hardening_fields as $field ) {
                    rsssl_update_option( $field, false );
                }
            }

			// Disable Email login protection
			rsssl_update_option( 'login_protection_enabled', false );

			// Disable Mixed Content Fixer
			rsssl_update_option( 'mixed_content_fixer', false );

			// Disable firewall
			rsssl_update_option( 'enable_firewall', false );
			rsssl_update_option( 'event_log_enabled', false );
			// Check if PRO version is active, then deactivate premium features
			if ( defined( 'rsssl_pro' ) ) {
				// Disable Two-Factor Authentication
				rsssl_update_option( 'two_fa_enabled_roles_totp', [] );

				// Disable Limit Login Attempts
				rsssl_update_option( 'enable_limited_login_attempts', false );

				// Disable advanced security headers
				$security_headers = [
					'upgrade_insecure_requests',
					'x_content_type_options',
					'hsts',
					'x_xss_protection',
					'x_frame_options',
					'referrer_policy',
					'csp_frame_ancestors',
				];
				foreach ( $security_headers as $header_key => $header_value ) {
					if ( is_string( $header_key ) ) {
						rsssl_update_option( $header_key, false );
					} else {
						rsssl_update_option( $header_value, false );
					}
				}

				// Deactivate password security enforcement
				rsssl_update_option( 'enforce_password_security_enabled', false );
				rsssl_update_option( 'enable_hibp_check', false );
			}

			rsssl_request_managed_rule_rebuild();
			WP_CLI::success( 'Recommended features deactivated.' );
		} catch ( Exception $e ) {
			WP_CLI::error( 'Failed to deactivate recommended features: ' . $e->getMessage() );
		}
	}

	/**
	 * Activate all recommended hardening features via CLI
	 *
	 * return void
	 */
	public function activate_recommended_hardening_features() {
		if ( ! $this->check_pro_command_preconditions() ) return;
		try {
            if (isset(RSSSL()->settingsConfigService)) {
                $recommended_hardening_fields = RSSSL()->settingsConfigService->getRecommendedHardeningSettings();
                foreach ( $recommended_hardening_fields as $field ) {
                    rsssl_update_option( $field, true );
                }
            }
			rsssl_request_managed_rule_rebuild();
			WP_CLI::success( 'Recommended hardening features activated.' );
		} catch ( Exception $e ) {
			WP_CLI::error( 'Failed to activate recommended hardening features: ' . $e->getMessage() );
		}
	}

	/**
	 * Deactivate all recommended features via CLI
	 *
	 * return void
	 */
	public function deactivate_recommended_hardening_features() {
		if ( ! $this->check_pro_command_preconditions() ) return;
		try {
            if (isset(RSSSL()->settingsConfigService)) {
                $recommended_hardening_fields = RSSSL()->settingsConfigService->getRecommendedHardeningSettings();
                foreach ( $recommended_hardening_fields as $field ) {
                    rsssl_update_option( $field, false );
                }
            }
			rsssl_request_managed_rule_rebuild();
			WP_CLI::success( 'Recommended hardening features deactivated.' );
		} catch ( Exception $e ) {
			WP_CLI::error( 'Failed to deactivate recommended hardening features: ' . $e->getMessage() );
		}
	}


	/**
	 * Activate recommended security headers via CLI
	 */
	public function activate_security_headers() {
        if ( ! $this->check_pro_command_preconditions() ) return;
        try {
            foreach (RSSSL()->headers->get_recommended_security_headers() as $header ) {
                if (isset($header['option_name'], $header['recommended_setting'])) {
                    rsssl_update_option( $header['option_name'], $header['recommended_setting'] );
                }
            }
            rsssl_request_advanced_headers_rebuild();
            WP_CLI::success( 'Recommended security headers activated.' );
        } catch ( Exception $e ) {
            WP_CLI::error( 'Failed to activate security headers: ' . $e->getMessage() );
        }
    }


	/**
	 * Deactivate recommended security headers via CLI
	 */
	public function deactivate_security_headers() {
		if ( ! $this->check_pro_command_preconditions() ) return;
		try {
			$recommended_headers = RSSSL()->headers->get_recommended_security_headers();

			foreach ( $recommended_headers as $header ) {
                if ( isset( $header['option_name'] ) && isset( $header['disabled_setting'] ) ) {
                    rsssl_update_option($header['option_name'], $header['disabled_setting']);
                }
			}
			rsssl_request_advanced_headers_rebuild();
			WP_CLI::success( 'Recommended security headers deactivated.' );
		} catch ( Exception $e ) {
			WP_CLI::error( 'Failed to deactivate security headers: ' . $e->getMessage() );
		}
	}

	/**
	 * Activate firewall via CLI
	 *
	 * return void
	 */

	public function activate_firewall() {
		if ( ! $this->check_pro_command_preconditions() ) return;
		try {
			rsssl_update_option( 'enable_firewall', true );
			rsssl_update_option( 'event_log_enabled', true );
			rsssl_request_managed_rule_rebuild();
			WP_CLI::success( 'Firewall activated.' );
		} catch ( Exception $e ) {
			WP_CLI::error( 'Failed to activate firewall: ' . $e->getMessage() );
		}
	}

	/**
	 * Deactivate firewall via CLI
	 *
	 * return void
	 */
	public function deactivate_firewall() {
		if ( ! $this->check_pro_command_preconditions() ) return;
		try {
			rsssl_update_option( 'enable_firewall', false );
			rsssl_update_option( 'event_log_enabled', false );
			rsssl_request_managed_rule_rebuild();
			WP_CLI::success( 'Firewall deactivated.' );
		} catch ( Exception $e ) {
			WP_CLI::error( 'Failed to deactivate firewall: ' . $e->getMessage() );
		}
	}

	/**
	 * Activate Two-Factor Authentication via CLI
	 *
	 * return void
	 */
	public function activate_2fa() {
		if ( ! $this->check_pro_command_preconditions() ) return;
		try {
			rsssl_update_option( 'two_fa_enabled_roles_totp', [ 'administrator' ] );
			rsssl_update_option( 'login_protection_enabled', true );
			WP_CLI::success( 'Two-Factor Authentication activated.' );
		} catch ( Exception $e ) {
			WP_CLI::error( 'Failed to activate Two-Factor Authentication: ' . $e->getMessage() );
		}
	}

	/**
	 * Deactivate Two-Factor Authentication via CLI
	 *
	 * return void
	 */
	public function deactivate_2fa() {
		if ( ! $this->check_pro_command_preconditions() ) return;
		try {
			rsssl_update_option( 'two_fa_enabled_roles_totp', [] );
			rsssl_update_option( 'login_protection_enabled', false );
			WP_CLI::success( 'Two-Factor Authentication deactivated.' );
		} catch ( Exception $e ) {
			WP_CLI::error( 'Failed to deactivate Two-Factor Authentication: ' . $e->getMessage() );
		}
	}

	/**
	 * Activate password security via CLI
	 *
	 * return void
	 */
	public function activate_password_security() {
		if ( ! $this->check_pro_command_preconditions() ) return;
		try {
			rsssl_update_option( 'enforce_password_security_enabled', true );
			rsssl_update_option( 'enforce_frequent_password_change', true );
			rsssl_update_option( 'hide_rememberme', true );
			rsssl_update_option( 'enable_hibp_check', true );
			WP_CLI::success( 'Password security features activated.' );
		} catch ( Exception $e ) {
			WP_CLI::error( 'Failed to activate password security: ' . $e->getMessage() );
		}
	}

	/**
	 * Deactivate password security via CLI
	 *
	 * return void
	 */
	public function deactivate_password_security() {
		if ( ! $this->check_pro_command_preconditions() ) return;
		try {
			rsssl_update_option( 'enforce_password_security_enabled', false );
            rsssl_update_option( 'enforce_frequent_password_change', false );
            rsssl_update_option( 'hide_rememberme', false );
			rsssl_update_option( 'enable_hibp_check', false );
			WP_CLI::success( 'Password security features deactivated.' );
		} catch ( Exception $e ) {
			WP_CLI::error( 'Failed to deactivate password security: ' . $e->getMessage() );
		}
	}

	/**
	 * Activate login attempts limitation via CLI
	 *
	 * return void
	 */
	public function activate_lla() {
		if ( ! $this->check_pro_command_preconditions() ) return;
		try {
			rsssl_update_option( 'enable_limited_login_attempts', true );
			rsssl_update_option( 'event_log_enabled', true );
			WP_CLI::success( 'Limit login attempts activated.' );
		} catch ( Exception $e ) {
			WP_CLI::error( 'Failed to activate limit login attempts: ' . $e->getMessage() );
		}
	}

	/**
	 * Deactivate login attempts limitation via CLI
	 *
	 * return void
	 */
	public function deactivate_lla() {
		if ( ! $this->check_pro_command_preconditions() ) return;
		try {
			rsssl_update_option( 'enable_limited_login_attempts', false );
			rsssl_update_option( 'event_log_enabled', false );
			WP_CLI::success( 'Limit login attempts deactivated.' );
		} catch ( Exception $e ) {
			WP_CLI::error( 'Failed to deactivate limit login attempts: ' . $e->getMessage() );
		}
	}

	/**
	 * Activate vulnerability scanning via CLI
	 *
	 * return void
	 */
	public function activate_vulnerability_scanning() {
		if ( ! $this->check_pro_command_preconditions() ) return;
		try {
			rsssl_update_option( 'enable_vulnerability_scanner', true );

			WP_CLI::success( 'Vulnerability scanning activated.' );
		} catch ( Exception $e ) {
			WP_CLI::error( 'Failed to activate vulnerability scanning: ' . $e->getMessage() );
		}
	}

	/**
	 * Deactivate vulnerability scanning via CLI
	 *
	 * return void
	 */
	public function deactivate_vulnerability_scanning() {
		if ( ! $this->check_pro_command_preconditions() ) return;
		try {
			rsssl_update_option( 'enable_vulnerability_scanner', false );

			WP_CLI::success( 'Vulnerability scanning deactivated.' );
		} catch ( Exception $e ) {
			WP_CLI::error( 'Failed to deactivate vulnerability scanning: ' . $e->getMessage() );
		}
	}

	/**
	 * Activate license via CLI
	 *
	 * @param array $args Positional arguments. License should be passed as first and only argument
	 *
	 * @return void
	 */
	public function activate_license( $args ) {
		if ( ! $this->check_pro_command_preconditions(true) ) return;
		try {
			// Check if license key is provided
			if ( empty( $args[0] ) ) {
				WP_CLI::error( 'Please provide a license key: wp rsssl activate_license YOUR_LICENSE_KEY' );

				return;
			}

			$license_key = sanitize_text_field( $args[0] );

			rsssl_update_option( 'license', $this->encrypt_with_prefix( $license_key, 'really_simple_ssl_' ) );
			$status = RSSSL()->licensing->get_license_status( 'check_license', true );

			update_option( 'rsssl_onboarding_dismissed', true, false );

			if ( $status === 'valid' ) {
				WP_CLI::success( 'License activated successfully.' );
			} elseif ( $status === 'invalid' || $status === 'missing' ) {
				WP_CLI::error( 'Invalid license key. You can find your license key on https://really-simple-ssl.com/account' );
			} elseif ( $status === 'expired' ) {
				WP_CLI::error( 'License has expired. Please renew via https://really-simple-ssl.com/account/subscriptions' );
			} elseif ( $status === 'no_activations_left' ) {
				WP_CLI::error( 'No activations left. Please upgrade your license via https://really-simple-ssl.com/account/subscriptions' );
			} elseif ( $status === 'disabled' ) {
				WP_CLI::error( 'This license is not valid. Find out why on your account page at https://really-simple-ssl.com/account' );
			}
		} catch ( Exception $e ) {
			WP_CLI::error( 'Failed to activate license: ' . $e->getMessage() );
		}
	}

	/**
	 * Deactivate license via CLI
	 *
	 * @return void
	 */
	public function deactivate_license() {
		if ( ! $this->check_pro_command_preconditions() ) return;
		try {
			rsssl_update_option( 'license', '' );
			$status = RSSSL()->licensing->get_license_status( 'check_license', true );
			update_option( 'rsssl_onboarding_dismissed', true, false );

			// License key should now be empty
			if ( $status === 'empty' ) {
				WP_CLI::success( 'License deactivated successfully.' );
			} else {
				WP_CLI::error( 'Something went wrong when deactivating your license. Please try again.' );
			}

		} catch ( Exception $e ) {
			WP_CLI::error( 'Failed to deactivate license: ' . $e->getMessage() );
		}
	}

	/**
	 * Add lock file for safe mode
	 *
	 * @return void
	 */
	public function add_lock_file() {
		if ( ! $this->check_pro_command_preconditions() ) return;
		try {
			$lock_file = WP_CONTENT_DIR . '/rsssl-safe-mode.lock';

			// Check if file already exists
			if ( file_exists( $lock_file ) ) {
				WP_CLI::warning( 'Lock file already exists.' );

				return;
			}

			// Create lock file
			$result = file_put_contents( $lock_file, time() );

			if ( $result === false ) {
				WP_CLI::error( 'Unable to create lock file.' );
			}

			// Set proper permissions
			chmod( $lock_file, 0644 );

			WP_CLI::success( 'Safe mode lock file created successfully.' );
		} catch ( Exception $e ) {
			WP_CLI::error( 'Failed to create lock file: ' . $e->getMessage() );
		}
	}

	/**
	 * Remove lock file for safe mode
	 *
	 * @return void
	 */
	public function remove_lock_file() {
		if ( ! $this->check_pro_command_preconditions() ) return;
		try {
			$lock_file = WP_CONTENT_DIR . '/rsssl-safe-mode.lock';

			// Check if file exists
			if ( ! file_exists( $lock_file ) ) {
				WP_CLI::warning( 'Lock file does not exist.' );

				return;
			}

			// Remove lock file
			if ( ! unlink( $lock_file ) ) {
				WP_CLI::error( 'Unable to remove lock file.' );
			}

			WP_CLI::success( 'Safe mode lock file removed successfully.' );
		} catch ( Exception $e ) {
			WP_CLI::error( 'Failed to remove lock file: ' . $e->getMessage() );
		}
	}

	/**
	 * Reset the 2FA status of a user to disabled
	 *
	 * Usage: wp rsssl reset_2fa 123
	 *
	 * @param array $args User ID should be the first element
	 *
	 * @throws \WP_CLI\ExitException
	 */
	public function reset_2fa( $args ): void
    {
        if ( ! $this->check_pro_command_preconditions() ) return;
        // When empty array is passed, WP_CLI will return an error
        if ( empty( $args ) ) {
            WP_CLI::error( 'Please provide a user ID.', true );
        }
        $user_id = intval( $args[0] );
        $user = get_user_by('id', $user_id);

        if (empty($user)) {
            WP_CLI::error('User not found.', true);
        }

        if (!class_exists('Rsssl_Two_Fa_Status')) {
            require_once rsssl_path . '/security/wordpress/two-fa/class-rsssl-two-fa-status.php';
        }

	    if ( $user ) {
		    // Delete all 2fa related user meta.
		    Rsssl_Two_Fa_Status::delete_two_fa_meta( $user->ID );
		    // Set the last login to now, so the user will be forced to use 2fa.
		    update_user_meta( $user->ID, 'rsssl_two_fa_last_login', gmdate( 'Y-m-d H:i:s' ) );
		    delete_user_meta( $user->ID, 'rsssl_passkey_configured'); // Remove passkey configuration if it exists
	    }

        WP_CLI::success( 'Successfully reset 2FA for user id ' . $user_id );
	}

    /**
     * Preview (dry-run) which users are in scope for 2FA reminders, optionally across subsites.
     *
     * Usage examples:
     *   wp rsssl twofa_preview
     *   wp rsssl twofa_preview --role=editor
     *   wp rsssl twofa_preview --include-subsites
     *   wp rsssl twofa_preview --site=7 --format=json
     *   wp rsssl twofa_preview --reset-meta
     */
    public function twofa_preview( $args, $assoc_args ) {
        if ( ! $this->check_pro_command_preconditions() ) return;

        $role           = $assoc_args['role'] ?? 'all';
        $format         = $assoc_args['format'] ?? 'table';
        $includeNetwork = \WP_CLI\Utils\get_flag_value( $assoc_args, 'include-subsites', false );
        $specificSiteId = $assoc_args['site'] ?? null;
        $doResetMeta    = \WP_CLI\Utils\get_flag_value( $assoc_args, 'reset-meta', false );

        $rows = $this->collect_twofa_rows( $role, $includeNetwork, $specificSiteId, $doResetMeta );

        if ( empty( $rows ) ) {
            \WP_CLI::success( 'Geen gebruikers gevonden in de huidige 2FA scope.' );
            return;
        }

        \WP_CLI\Utils\format_items( $format, $rows, [ 'blog_id','user_id','user_login','email','roles','reminder_sent' ] );
    }

    /**
     * Send 2FA reminders for the current selection. Explicitly triggers the send flow per (sub)site.
     *
     * Usage examples:
     *   wp rsssl twofa_send
     *   wp rsssl twofa_send --role=author --site=3
     *   wp rsssl twofa_send --include-subsites --reset-meta
     */
    public function twofa_send( $args, $assoc_args ) {
        if ( ! $this->check_pro_command_preconditions() ) return;

        $role           = $assoc_args['role'] ?? 'all';
        $includeNetwork = \WP_CLI\Utils\get_flag_value( $assoc_args, 'include-subsites', false );
        $specificSiteId = $assoc_args['site'] ?? null;
        $doResetMeta    = \WP_CLI\Utils\get_flag_value( $assoc_args, 'reset-meta', false );

        $service = new Rsssl_Two_Fa_Reminder_Service();
        $siteIds = $this->determine_sites_for_twofa( $includeNetwork, $specificSiteId );
        $total   = 0;

        foreach ( $siteIds as $blog_id ) {
            $this->with_blog_for_twofa( (int) $blog_id, function() use ( $role, $service, $doResetMeta, &$total, $blog_id ) {
                $repo   = new Rsssl_Two_Fa_User_Repository();
                $params = new Rsssl_Two_FA_Data_Parameters([
                    'filter_column' => 'user_role',
                    'filter_value'  => $role,
                ]);
                $collection = $repo->getForcedTwoFaUsersWithOpenStatus( $params );

                if ( $doResetMeta ) {
                    foreach ( $collection->getUsers() as $u ) {
                        delete_user_meta( $u->getId(), 'rsssl_two_fa_reminder_sent' );
                    }
                }

                $countBefore = (int) $collection->getTotalRecords();
                if ( $countBefore > 0 ) {
                    \WP_CLI::log( sprintf( 'Blog %d: verstuur reminders naar %d gebruiker(s)...', (int) $blog_id, $countBefore ) );
                    $service->processReminders( $collection );
                    $total += $countBefore;
                } else {
                    \WP_CLI::log( sprintf( 'Blog %d: geen kandidaten.', (int) $blog_id ) );
                }
            } );
        }

        \WP_CLI::success( sprintf( 'Verzenden gereed. Totaal verstuurd: %d', (int) $total ) );
    }

    /** ----------------- Helpers (private) ----------------- */

    /**
     * Build preview rows for users in scope.
     */
    private function collect_twofa_rows( string $role, bool $includeNetwork, $specificSiteId, bool $doResetMeta ): array {
        $rows    = [];
        $siteIds = $this->determine_sites_for_twofa( $includeNetwork, $specificSiteId );

        foreach ( $siteIds as $blog_id ) {
            $this->with_blog_for_twofa( (int) $blog_id, function() use ( $role, $doResetMeta, $blog_id, &$rows ) {
                $repo   = new Rsssl_Two_Fa_User_Repository();
                $params = new Rsssl_Two_FA_Data_Parameters([
                    'filter_column' => 'user_role',
                    'filter_value'  => $role,
                ]);

	            foreach ( $repo->getForcedTwoFaUsersWithOpenStatus( $params )->getUsers() as $u ) {
                    $user_id = (int) $u->getId();
                    $wp_user = get_userdata( $user_id );
                    if ( ! $wp_user ) {
                        continue;
                    }

                    if ( $doResetMeta ) {
                        delete_user_meta( $user_id, 'rsssl_two_fa_reminder_sent' );
                    }

                    $rows[] = [
                        'blog_id'       => (string) $blog_id,
                        'user_id'       => (string) $user_id,
                        'user_login'    => $wp_user->user_login,
                        'email'         => $wp_user->user_email,
                        'roles'         => implode( ',', $wp_user->roles ?? [] ),
                        'reminder_sent' => get_user_meta( $user_id, 'rsssl_two_fa_reminder_sent', true ) ? 'yes' : 'no',
                    ];
                }
            } );
        }

        return $rows;
    }

    /**
     * Decide which sites to traverse for multisite support.
     */
    private function determine_sites_for_twofa( bool $includeNetwork, $specificSiteId ): array {
        if ( is_multisite() ) {
            if ( ! empty( $specificSiteId ) ) {
                return [ (int) $specificSiteId ];
            }
            if ( $includeNetwork ) {
                $ids = [];
                foreach ( get_sites( [ 'fields' => 'ids', 'number' => 0 ] ) as $bid ) {
                    $ids[] = (int) $bid;
                }
                return $ids;
            }
            return [ get_current_blog_id() ];
        }
        return [ 0 ];
    }

    /**
     * Execute a callback within the context of a (sub)site.
     */
    private function with_blog_for_twofa( int $blog_id, callable $cb ): void {
        if ( is_multisite() && $blog_id > 0 ) {
            switch_to_blog( $blog_id );
            try {
                $cb();
            } finally {
                restore_current_blog();
            }
        } else {
            $cb();
        }
    }

	/**
	 * Update the advanced-headers.php with the latest rules
	 *
	 * @return void
	 */
	public function update_advanced_headers() {
		if ( ! $this->check_pro_command_preconditions() ) return;
		rsssl_request_advanced_headers_rebuild();
        WP_CLI::success( 'Successfully update advanced headers.' );
	}

    /**
     * Add an IP to the firewall blocklist.
     *
     * @example wp rsssl add_firewall_ip_block 123.123.123.1 --note="This is a temporary block"
     * @example wp rsssl add_firewall_ip_block 123.123.123.1 --permanent --note="This is a permanent block"
     *
     * @param array $args Should contain IP as the first element
     * @param array $assoc_args Can contain a note with a 'note' key
     */
    public function add_firewall_ip_block(array $args, array $assoc_args): void
    {
        if ( ! $this->check_pro_command_preconditions() ) return;
        $this->handleFirewallTableEntry($args, $assoc_args, 'blocked', 'add');
    }

	/**
     * Can be used to remove a (temporary) block from the firewall blocklist.
     * @example wp rsssl remove_firewall_ip_block 123.123.123.1
     *
	 * @param $args array Should contain the ip address
	 */
	public function remove_firewall_ip_block(array $args, array $assoc_args ): void
    {
        if ( ! $this->check_pro_command_preconditions() ) return;
        $this->handleFirewallTableEntry($args, $assoc_args, 'blocked', 'remove');
	}

    /**
     * Return a table of the current blocked IPs with the headers:
     * IP Address, Note, Permanent
     */
    public function show_blocked_ips() {
        if ( ! $this->check_pro_command_preconditions() ) return;
        $columns = [
            'ip_address',
            'note',
            'permanent',
        ];

	    $blockedIps = ( new Rsssl_404_Block() )->get_blocked_ips($columns);

        WP_CLI\Utils\format_items('table', $blockedIps, $columns);
    }

	/**
	 * Add an IP to the firewall's trusted list.
	 *
	 * Usage: wp rsssl add_firewall_trusted_ip 123.123.123.1
	 *
	 * @param array $args Should contain IP as the first element
	 * @param array $assoc_args Can contain a note with a 'note' key
     * @uses handleFirewallTableEntry()
	 */
	public function add_firewall_trusted_ip(array $args, array $assoc_args) {
        if ( ! $this->check_pro_command_preconditions() ) return;
        $this->handleFirewallTableEntry($args, $assoc_args, 'trusted', 'add');
	}

    /**
     * Remove an IP from the firewall's trusted list.
     *
     * Usage: wp rsssl remove_firewall_trusted_ip 123.123.123.1
     *
     * @param array $args Should contain IP as the first element
     * @param array $assoc_args Can contain a note with a 'note' key
     * @uses handleFirewallTableEntry()
     */
    public function remove_firewall_trusted_ip(array $args, array $assoc_args) {
        if ( ! $this->check_pro_command_preconditions() ) return;
        $this->handleFirewallTableEntry($args, $assoc_args, 'trusted', 'remove');
    }

    /**
     * Add an IP to the LLA's trusted list.
     *
     * Usage: wp rsssl add_lla_trusted_ip 123.123.123.1
     *
     * @param array $args Command arguments.
     * @uses handleLlaTableEntry()
     */
    public function add_lla_trusted_ip( $args ) {
        if ( ! $this->check_pro_command_preconditions() ) return;
        $this->handleLlaTableEntry($args, 'allowed', 'source_ip', 'add');
    }

    /**
     * Add an IP to the LLA's blocklist.
     *
     * Usage: wp rsssl remove_lla_trusted_ip 123.123.123.1
     *
     * @param array $args Command arguments.
     * @uses handleLlaTableEntry()
     */
    public function remove_lla_trusted_ip( $args ) {
        if ( ! $this->check_pro_command_preconditions() ) return;
        $this->handleLlaTableEntry($args, 'allowed', 'source_ip', 'remove');
    }

    /**
     * Remove an IP from the LLA's trusted list.
     *
     * Usage: wp rsssl add_lla_blocked_ip 123.123.123.1
     * Usage: wp rsssl add_lla_blocked_ip 123.123.123.1 --permanent
     *
     * @param array $args Command arguments.
     * @param array $assoc_args Associative arguments.
     * @uses handleLlaTableEntry()
     */
    public function add_lla_blocked_ip( $args, $assoc_args ) {
        if ( ! $this->check_pro_command_preconditions() ) return;
        $status = (isset($assoc_args['permanent']) ? 'blocked' : 'locked');
        $this->handleLlaTableEntry($args, $status, 'source_ip', 'add');
    }

    /**
     * Remove an IP from the LLA's blocklist.
     *
     * Usage: wp rsssl remove_lla_blocked_ip 123.123.123.1
     * Usage: wp rsssl remove_lla_blocked_ip 123.123.123.1 --permanent
     *
     * @param array $args Command arguments.
     * @param array $assoc_args Associative arguments.
     * @uses handleLlaTableEntry()
     */
    public function remove_lla_blocked_ip( $args, $assoc_args ) {
        if ( ! $this->check_pro_command_preconditions() ) return;
        $status = (isset($assoc_args['permanent']) ? 'blocked' : 'locked');
        $this->handleLlaTableEntry($args, $status, 'source_ip', 'remove');
    }

    /**
     * Add a username to the LLA's trusted list.
     *
     * Usage: wp rsssl add_lla_trusted_username username
     *
     * @param array $args Command arguments.
     * @uses handleLlaTableEntry()
     */
    public function add_lla_trusted_username( $args ) {
        if ( ! $this->check_pro_command_preconditions() ) return;
        $this->handleLlaTableEntry($args, 'allowed', 'username', 'add');
    }

    /**
     * Remove a username to the LLA's trusted list.
     *
     * Usage: wp rsssl remove_lla_trusted_username username
     *
     * @param array $args Command arguments.
     * @uses handleLlaTableEntry()
     */
    public function remove_lla_trusted_username( $args ) {
        if ( ! $this->check_pro_command_preconditions() ) return;
        $this->handleLlaTableEntry($args, 'allowed', 'username', 'remove');
    }

    /**
     * Add a username to the LLA's blocked list.
     *
     * Usage: wp rsssl add_lla_blocked_username username
     * Usage: wp rsssl add_lla_blocked_username username --permanent
     *
     * @param array $args Command arguments.
     * @param array $assoc_args Associative arguments.
     * @uses handleLlaTableEntry()
     */
    public function add_lla_blocked_username( array $args, array $assoc_args ) {
        if ( ! $this->check_pro_command_preconditions() ) return;
        $status = (isset($assoc_args['permanent']) ? 'blocked' : 'locked');
        $this->handleLlaTableEntry($args, $status, 'username', 'add');
    }

    /**
     * Remove a username to the LLA's blocked list.
     *
     * Usage: wp rsssl remove_lla_blocked_username username
     * Usage: wp rsssl remove_lla_blocked_username username --permanent
     *
     * @param array $args Command arguments.
     * @param array $assoc_args Associative arguments.
     * @uses handleLlaTableEntry()
     */
    public function remove_lla_blocked_username( $args, $assoc_args ) {
        if ( ! $this->check_pro_command_preconditions() ) return;
        $status = (isset($assoc_args['permanent']) ? 'blocked' : 'locked');
        $this->handleLlaTableEntry($args, $status, 'username', 'remove');
    }

    /**
     * Handle an action for the firewall table for a specific IP address.
     *
     * @param array $args Command arguments.
     * @param array $assoc_args Associative arguments.
     * @param string $status Should be either 'trusted' or 'blocked'.
     * @param string $action Should be either 'add' or 'remove'.
     *
     * @uses remove_white_list_ip() & add_white_list_ip() from Rsssl_Geo_Block -
     * Those also handle a block request for an IP address.
     */
    protected function handleFirewallTableEntry(array $args, array $assoc_args, string $status, string $action)
    {
        if (rsssl_get_option('enable_firewall', false) !== true) {
            WP_CLI::error('The firewall is not enabled.', true);
        }

        if (!in_array($status, ['trusted', 'blocked']) || !in_array($action, ['add', 'remove'])) {
            WP_CLI::error('Could not handle action for the firewall table.', true);
        }

        if (empty($args[0])) {
            WP_CLI::error('Please provide an IP address.', true);
        }

        $ip = $this->getFilteredIpAddress($args[0]);

        // Prepare data for adding to the whitelist.
        $data = [
            'ip_address' => $ip,
            'note'       => $assoc_args['note'] ?? '',
            'status'     => $status,
            'permanent'  => isset($assoc_args['permanent']),
        ];

        // Use the Rsssl_Geo_Block class to add the trusted IP.
        if (!class_exists('\RSSSL\Pro\Security\WordPress\Rsssl_Geo_Block')) {
            require_once rsssl_path . 'pro/security/wordpress/rsssl-geo-block.php';
        }

        try {
            $geo_block = new \RSSSL\Pro\Security\WordPress\Rsssl_Geo_Block();

            // fallback
            $response = ['success' => false, 'message' => 'Something went wrong!'];

            if ($action === 'remove') {
                $response = $geo_block->remove_white_list_ip( $data );
            }

            if ($action === 'add') {
                $response = $geo_block->add_white_list_ip( $data );
            }
        } catch ( \Exception $e ) {
            WP_CLI::error( 'Failed to handle IP entry: ' . $e->getMessage(), true );
        }

        // Handle response.
        if ( $response['success'] ) {
            WP_CLI::success( $response['message'] );
            return;
        }

        WP_CLI::error( $response['message'], true );
    }

    /**
     * Handle an action for the LLA table for a specific IP address.
     *
     * @param array $args Command arguments.
     * @param string $status Should be either 'allowed' or 'blocked'.
     * @param string $type Should be either 'source_ip' or 'username'.
     * @param string $action Should be either 'add' or 'remove'.
     * @return void
     */
    protected function handleLlaTableEntry(array $args, string $status, string $type, string $action): void
    {
        if (rsssl_get_option('enable_limited_login_attempts', false) !== true) {
            WP_CLI::error('The LLA feature is not enabled.', true);
        }

        if (empty($args[0])) {
            WP_CLI::error('Please provide the command the necessary arguments', true);
        }

        if (!in_array($status, ['allowed', 'blocked', 'locked']) || !in_array($type, ['source_ip', 'username'])) {
            WP_CLI::error('Something went wrong! Could not handle command.', true);
        }

        $value = '';
        if ($type === 'source_ip') {
            $value = $this->getFilteredIpAddress($args[0]);
        }

        if ($type === 'username') {
            $value = sanitize_text_field($args[0]);
        }

        // Use the Rsssl_Limit_Login_Admin class to add the trusted IP.
        if (!class_exists('\RSSSL\Pro\Security\WordPress\Rsssl_Limit_Login_Admin')) {
            require_once rsssl_path . 'pro/security/wordpress/class-rsssl-limit-login-admin.php';
        }

        try {
            $lla = new \RSSSL\Pro\Security\WordPress\Rsssl_Limit_Login_Admin();

            // fallback
            $response = ['success' => false, 'message' => 'Something went wrong!'];

            if ($action === 'add') {
                $response = $lla->handle_entity([
                    'value' => $value,
                    'status'  => sanitize_text_field($status),
                ], $type);
            }

            if ($action === 'remove') {
                $entry = $lla->get_entry($type, $value, $status);
                $response = $lla->delete_entries([
                    'id' => $entry['id'],
                ]);
            }
        } catch ( Exception $e ) {
            WP_CLI::error( 'Failed to handle LLA entry: ' . $e->getMessage(), true );
        }

        // Handle response.
        if ( $response['success'] ) {
            WP_CLI::success( $response['message'] );
            return;
        }

        WP_CLI::error( $response['message'], true );
    }

    /**
     * Return a filtered IP address. Method will exit() if the IP address is
     * invalid with the WP_CLI error message: Invalid IP address provided.
     */
    protected function getFilteredIpAddress(string $originalIp): string
    {
        // Check if the input is potentially a CIDR
        if (strpos($originalIp, '/') !== false) {
            list($address, $mask_str) = explode('/', $originalIp, 2);

            // Validate the IP address part
            if (!filter_var($address, FILTER_VALIDATE_IP)) {
                WP_CLI::error('Invalid IP address part in CIDR notation: ' . $address, true);
            }

            // Validate the mask part
            if (!is_numeric($mask_str)) {
                WP_CLI::error('CIDR mask is not numeric: ' . $mask_str, true);
            }
            $mask = (int)$mask_str;

            // Determine IP version for mask validation
            $is_ipv4 = filter_var($address, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4);
            $is_ipv6 = filter_var($address, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6);

            if ($is_ipv4) {
                if ($mask < 0 || $mask > 32) {
                    WP_CLI::error('Invalid IPv4 CIDR mask (must be 0-32): ' . $mask, true);
                }
            } elseif ($is_ipv6) {
                if ($mask < 0 || $mask > 128) {
                    WP_CLI::error('Invalid IPv6 CIDR mask (must be 0-128): ' . $mask, true);
                }
            } else {
                // This case should ideally not be reached if filter_var($address, FILTER_VALIDATE_IP) passed
                WP_CLI::error('Unknown IP address type for CIDR validation: ' . $address, true);
            }

            // If all checks pass for CIDR, return the original CIDR string
            return $originalIp;

        } else {
            // Validate as a plain IP address
            $ip = filter_var($originalIp, FILTER_VALIDATE_IP);
            if (empty($ip)) {
                WP_CLI::error('Invalid IP address provided: ' . $originalIp, true);
            }
            return $ip;
        }
    }

	/**
	 * Performs pre-flight checks before SSL activation.
	 * Checks for HTTPS reachability and potentially other issues like .htaccess writability.
	 *
	 * @return array ['success' => bool, 'message' => string, 'warnings' => array]
	 */
	private function perform_pre_flight_checks(): array {
		$warnings = [];
		$message = '';

		// --- Check 1: HTTPS Reachability ---
		$home_url = home_url();
		$https_url = set_url_scheme( $home_url, 'https' );

		// Use wp_remote_get to see if the HTTPS version is reachable
		// 'sslverify' => false is important for local/staging with self-signed certs
		// Timeout set low to avoid long waits on failure
		$response = wp_remote_get( $https_url, [
			'timeout'   => 10, // seconds
			'sslverify' => false,
			'redirection' => 5, // Follow redirects
		] );

		if ( is_wp_error( $response ) ) {
			$error_code = $response->get_error_code();
			$error_message = $response->get_error_message();
			$friendly_message = sprintf(
				__( 'Failed to reach %s. The site does not appear to be accessible over HTTPS. Please ensure your server is configured for SSL.', 'really-simple-ssl' ),
				$https_url
			);

			// Check if WP_DEBUG is enabled
			$wp_debug_enabled = ( defined( 'WP_DEBUG' ) && WP_DEBUG );

			if ( $wp_debug_enabled ) {
				// Log the detailed error when WP_DEBUG is on
				// Using WP_CLI::debug requires the --debug flag for wp-cli command itself
				 WP_CLI::debug( sprintf( "HTTPS Check Error Details: Code=%s, Message=%s", $error_code, $error_message ), 'rsssl-cli-debug' );
				 // Alternatively, or in addition, use standard PHP error logging:
				 // error_log( sprintf("Really Simple SSL WP-CLI HTTPS Check Error: Code=%s, Message=%s", $error_code, $error_message) );

				 // Optionally, still show a slightly more informative message than the friendly one
				 $message_to_show = sprintf(
					__( 'Failed to reach %s. The site does not appear to be accessible over HTTPS (Error: %s). Check debug logs for details.', 'really-simple-ssl' ),
					 $https_url,
					 $error_code // Show the code, but maybe not the full verbose message
				 );
			} else {
				// Show only the user-friendly message if WP_DEBUG is off
				$message_to_show = $friendly_message;
			}

			return [
				'success' => false,
				'message' => $message_to_show,
				'warnings' => $warnings
			];

		} else {
			// Connected, check the response code
			$response_code = wp_remote_retrieve_response_code( $response );
			if ( $response_code < 200 || $response_code >= 400 ) {
				// Reached server, but got an error response (e.g., 404 Not Found, 500 Internal Server Error)
				 return [
					'success' => false,
					'message' => sprintf( __( 'Reached %s, but received an error response code: %d. HTTPS is not properly configured.', 'really-simple-ssl' ), $https_url, $response_code ),
					'warnings' => $warnings
				 ];
			}
			// If response code is 2xx or 3xx, we consider HTTPS reachable.
			// A more robust check could analyze the body for expected content, but this is usually sufficient.
		}

		// --- Check 2: .htaccess Writability (if needed) ---
		// Keep the previous check for .htaccess if the redirect method is set to htaccess
		// $htaccess_writable = true; // Replace with actual check logic (e.g., check if WP_Filesystem allows writing)
		if ( rsssl_get_option('redirect') === 'htaccess' ) {
			$htaccess_manager = RSSSL_Htaccess_File_Manager::get_instance();
			// Match CLI diagnostics to the same resolved target path the runtime writer will use.
			$htaccess_file = $htaccess_manager->get_root_htaccess_target_path();
			if ( $htaccess_file !== '' && ! is_writable( $htaccess_file ) ) {
				$warnings[] = sprintf( __( '.htaccess file (%s) is not writable. Redirects cannot be configured automatically.', 'really-simple-ssl' ), $htaccess_file );
				// This remains a warning, as activation might still work partially (WP URLs change)
			}
		}

		// Add more checks as needed (e.g., specific certificate details if possible/required)...

		$message = __( 'Pre-flight checks passed.', 'really-simple-ssl' );
		return ['success' => true, 'message' => $message, 'warnings' => $warnings];
	}

	/**
	 * Get command details for WP-CLI commands.
	 *
	 * @return array Command details.
	 */
	protected function get_command_list() {
		return [
			'activate_ssl'                      => [
				'description' => __( 'Activate SSL on the site.', 'really-simple-ssl' ),
				'synopsis'    => [],
				'pro'         => false,
			],
			'deactivate_ssl'                    => [
				'description' => __( 'Deactivate SSL on the site.', 'really-simple-ssl' ),
				'synopsis'    => [],
				'pro'         => false,
			],
			'update_option'                     => [
				'description' => __( 'Update a Really Simple Security option. Usage: wp rsssl update_option --name=option_name --value=option_value. Use 0 and 1 for booleans.', 'really-simple-ssl' ),
				'synopsis'    => [
					[
						'type'        => 'assoc',
						'name'        => 'name',
						'optional'    => false,
						'description' => __( 'Name of the option to update.', 'really-simple-ssl' ),
					],
					[
						'type'        => 'assoc',
						'name'        => 'value',
						'optional'    => false,
						'description' => __( 'Value to set for the option.', 'really-simple-ssl' ),
					],
				],
				'pro'         => false,
			],
			'activate_recommended_features'     => [
				'description' => __( 'Activate all recommended features.', 'really-simple-ssl' ),
				'synopsis'    => [],
				'pro'         => false,
			],
			'deactivate_recommended_features'   => [
				'description' => __( 'Deactivate all recommended features.', 'really-simple-ssl' ),
				'synopsis'    => [],
				'pro'         => false,
			],
			'activate_security_headers'         => [
				'description' => __( 'Activate essential security headers.', 'really-simple-ssl' ),
				'synopsis'    => [],
				'pro'         => true,
			],
			'deactivate_security_headers'       => [
				'description' => __( 'Deactivate essential security headers.', 'really-simple-ssl' ),
				'synopsis'    => [],
				'pro'         => true,
			],
			'activate_firewall'                 => [
				'description' => __( 'Activate the firewall.', 'really-simple-ssl' ),
				'synopsis'    => [],
				'pro'         => true,
			],
			'deactivate_firewall'               => [
				'description' => __( 'Deactivate the firewall.', 'really-simple-ssl' ),
				'synopsis'    => [],
				'pro'         => true,
			],
			'activate_2fa'                      => [
				'description' => __( 'Activate Two-Factor Authentication.', 'really-simple-ssl' ),
				'synopsis'    => [],
				'pro'         => false,
			],
			'deactivate_2fa'                    => [
				'description' => __( 'Deactivate Two-Factor Authentication.', 'really-simple-ssl' ),
				'synopsis'    => [],
				'pro'         => false,
			],
			'activate_password_security'        => [
				'description' => __( 'Activate password security features.', 'really-simple-ssl' ),
				'synopsis'    => [],
				'pro'         => true,
			],
			'deactivate_password_security'      => [
				'description' => __( 'Deactivate password security features.', 'really-simple-ssl' ),
				'synopsis'    => [],
				'pro'         => true,
			],
			'activate_lla'                      => [
				'description' => __( 'Activate limit login attempts.', 'really-simple-ssl' ),
				'synopsis'    => [],
				'pro'         => true,
			],
			'deactivate_lla'                    => [
				'description' => __( 'Deactivate limit login attempts.', 'really-simple-ssl' ),
				'synopsis'    => [],
				'pro'         => true,
			],
			'activate_vulnerability_scanning'   => [
				'description' => __( 'Activate vulnerability scanning.', 'really-simple-ssl' ),
				'synopsis'    => [],
				'pro'         => false,
			],
			'deactivate_vulnerability_scanning' => [
				'description' => __( 'Deactivate vulnerability scanning.', 'really-simple-ssl' ),
				'synopsis'    => [],
				'pro'         => false,
			],
			'activate_license'                  => [
				'description' => __( 'Activate a license key. Usage: wp rsssl activate_license YOUR_LICENSE_KEY.', 'really-simple-ssl' ),
				'synopsis'    => [
					[
						'type'        => 'positional',
						'name'        => 'license_key',
						'optional'    => false,
						'description' => __( 'The license key to activate.', 'really-simple-ssl' ),
					],
				],
				'pro'         => true,
			],
			'deactivate_license'                => [
				'description' => __( 'Deactivate the license.', 'really-simple-ssl' ),
				'synopsis'    => [],
				'pro'         => true,
			],
			'add_lock_file'                     => [
				'description' => __( 'Add a lock file for safe mode.', 'really-simple-ssl' ),
				'synopsis'    => [],
				'pro'         => false,
			],
			'remove_lock_file'                  => [
				'description' => __( 'Remove the lock file for safe mode.', 'really-simple-ssl' ),
				'synopsis'    => [],
				'pro'         => false,
			],
			'reset_2fa'    => [
				'description' => __( 'Reset the 2FA status and methods for a user.', 'really-simple-ssl' ),
				'synopsis'    => [
					[
						'type'        => 'positional',
						'name'        => 'user_id',
						'optional'    => false,
						'description' => __( 'The user ID to reset 2FA for.', 'really-simple-ssl' ),
					],
				],
				'pro'         => false,
			],
            'twofa_preview' => [
                'description' => __( 'Preview users in scope for 2FA reminders (dry-run).', 'really-simple-ssl' ),
                'synopsis'    => [
                    [ 'type' => 'assoc', 'name' => 'role',  'optional' => true,  'description' => __( 'Filter by user role (default: all).', 'really-simple-ssl' ) ],
                    [ 'type' => 'assoc', 'name' => 'site',  'optional' => true,  'description' => __( 'Limit to a single blog_id (multisite).', 'really-simple-ssl' ) ],
                    [ 'type' => 'flag',  'name' => 'include-subsites', 'optional' => true, 'description' => __( 'Traverse all subsites in the network.', 'really-simple-ssl' ) ],
                    [ 'type' => 'assoc', 'name' => 'format','optional' => true,  'description' => __( 'Output format: table|json|csv (default: table).', 'really-simple-ssl' ) ],
                    [ 'type' => 'flag',  'name' => 'reset-meta', 'optional' => true, 'description' => __( 'Reset rsssl_two_fa_reminder_sent meta for a clean run.', 'really-simple-ssl' ) ],
                ],
                'pro' => true,
            ],
            'twofa_send' => [
                'description' => __( 'Send 2FA reminders for the current selection.', 'really-simple-ssl' ),
                'synopsis'    => [
                    [ 'type' => 'assoc', 'name' => 'role',  'optional' => true,  'description' => __( 'Filter by user role (default: all).', 'really-simple-ssl' ) ],
                    [ 'type' => 'assoc', 'name' => 'site',  'optional' => true,  'description' => __( 'Limit to a single blog_id (multisite).', 'really-simple-ssl' ) ],
                    [ 'type' => 'flag',  'name' => 'include-subsites', 'optional' => true, 'description' => __( 'Traverse all subsites in the network.', 'really-simple-ssl' ) ],
                    [ 'type' => 'flag',  'name' => 'reset-meta', 'optional' => true, 'description' => __( 'Reset rsssl_two_fa_reminder_sent meta before sending.', 'really-simple-ssl' ) ],
                ],
                'pro' => true,
            ],
			'update_advanced_headers' => [
				'description' => __( 'Update the advanced-headers.php with the latest rules.', 'really-simple-ssl' ),
				'synopsis'    => [],
				'pro'         => false,
			],
            'add_firewall_ip_block' => [
                'description' => __( 'Add IP block.', 'really-simple-ssl' ),
                'synopsis'    => [
                    [
                        'type'        => 'positional',
                        'name'        => 'ip_address',
                        'optional'    => false,
                        'description' => __( 'The IP to block.', 'really-simple-ssl' ),
                    ],
                    [
                        'type'        => 'flag',
                        'name'        => 'permanent',
                        'optional'    => true,
                        'description' => __( 'Flag to add a permanent block.', 'really-simple-ssl' ),
                    ],
                    [
                        'type'        => 'assoc',
                        'name'        => 'note',
                        'optional'    => true,
                        'description' => __( 'Optional note for the block.', 'really-simple-ssl' ),
                    ],
                ],
                'pro'         => true,
            ],
			'remove_firewall_ip_block' => [
				'description' => __( 'Remove IP block.', 'really-simple-ssl' ),
                'synopsis'    => [
                    [
                        'type'        => 'positional',
                        'name'        => 'ip_address',
                        'optional'    => false,
                        'description' => __( 'The IP to remove the block for.', 'really-simple-ssl' ),
                    ],
                ],
				'pro'         => true,
			],
			'show_blocked_ips' => [
				'description' => __( 'Show blocked IP\'s.', 'really-simple-ssl' ),
				'synopsis'    => [],
				'pro'         => true,
			],
			'add_firewall_trusted_ip' => [
				'description' => __( 'Add a trusted IP to the firewall.', 'really-simple-ssl' ),
				'synopsis'    => [],
				'pro'         => true,
			],
            'remove_firewall_trusted_ip' => [
				'description' => __( 'Remove a trusted IP from the firewall.', 'really-simple-ssl' ),
				'synopsis'    => [],
				'pro'         => true,
			],
            'add_lla_trusted_ip' => [
                'description' => __( 'Add a trusted IP to the limit login attempts table.', 'really-simple-ssl' ),
                'synopsis'    => [],
                'pro'         => true,
            ],
            'remove_lla_trusted_ip' => [
                'description' => __( 'Remove a trusted IP from the limit login attempts table.', 'really-simple-ssl' ),
                'synopsis'    => [],
                'pro'         => true,
            ],
            'add_lla_blocked_ip' => [
                'description' => __( 'Add a blocked IP to the limit login attempts table.', 'really-simple-ssl' ),
                'synopsis'    => [
                    [
                        'type'        => 'positional',
                        'name'        => 'ip_address',
                        'optional'    => false,
                        'description' => __( 'The IP to block.', 'really-simple-ssl' ),
                    ],
                    [
                        'type'        => 'flag',
                        'name'        => 'permanent',
                        'optional'    => true,
                        'description' => __( 'Flag to add a permanent block.', 'really-simple-ssl' ),
                    ],
                ],
                'pro'         => true,
            ],
            'remove_lla_blocked_ip' => [
                'description' => __( 'Remove a blocked IP from the limit login attempts table.', 'really-simple-ssl' ),
                'synopsis'    => [
                    [
                        'type'        => 'positional',
                        'name'        => 'ip_address',
                        'optional'    => false,
                        'description' => __( 'The IP to block.', 'really-simple-ssl' ),
                    ],
                    [
                        'type'        => 'flag',
                        'name'        => 'permanent',
                        'optional'    => true,
                        'description' => __( 'Flag to add a permanent block.', 'really-simple-ssl' ),
                    ],
                ],
                'pro'         => true,
            ],
            'add_lla_trusted_username' => [
                'description' => __( 'Add a trusted username to the limit login attempts table.', 'really-simple-ssl' ),
                'synopsis'    => [],
                'pro'         => true,
            ],
            'remove_lla_trusted_username' => [
                'description' => __( 'Remove a trusted username from the limit login attempts table.', 'really-simple-ssl' ),
                'synopsis'    => [],
                'pro'         => true,
            ],
            'add_lla_blocked_username' => [
                'description' => __( 'Add a blocked username to the limit login attempts table.', 'really-simple-ssl' ),
                'synopsis'    => [
                    [
                        'type'        => 'positional',
                        'name'        => 'ip_address',
                        'optional'    => false,
                        'description' => __( 'The username to block.', 'really-simple-ssl' ),
                    ],
                    [
                        'type'        => 'flag',
                        'name'        => 'permanent',
                        'optional'    => true,
                        'description' => __( 'Flag to add a permanent block.', 'really-simple-ssl' ),
                    ],
                ],
                'pro'         => true,
            ],
            'remove_lla_blocked_username' => [
                'description' => __( 'Remove a blocked username from the limit login attempts table.', 'really-simple-ssl' ),
                'synopsis'    => [
                    [
                        'type'        => 'positional',
                        'name'        => 'username',
                        'optional'    => false,
                        'description' => __( 'The username to remove the block for.', 'really-simple-ssl' ),
                    ],
                    [
                        'type'        => 'flag',
                        'name'        => 'permanent',
                        'optional'    => true,
                        'description' => __( 'Flag to remove a permanent block.', 'really-simple-ssl' ),
                    ],
                ],
                'pro'         => true,
            ],
		];
	}

	/**
	 * This method registers our WP-CLI commands and uses {@see get_command_list()}
	 * to retrieve the list. Do not execute this method before the init hook.
	 */
	public function register_wp_cli_commands() {
		$command_details = $this->get_command_list();
		foreach ( $command_details as $command => $details ) {
			if ( isset( $details['inactive'] ) && $details['inactive'] === true ) {
				continue;
			}
			WP_CLI::add_command(
				"rsssl $command",
				[ $this, $command ],
				[
					'shortdesc' => $details['description'],
					'synopsis'  => $details['synopsis'],
				]
			);
		}

	}
}

// Add devtools command if present
if ( file_exists( rsssl_path . 'pro/assets/tools/cli/class-rsssl-stub-generator.php' ) ) {
	require_once rsssl_path . 'pro/assets/tools/cli/class-rsssl-stub-generator.php';
}
