<?php
/**
 * HTTPS Redirect Module
 *
 * Force HTTPS redirection for your WordPress site.
 *
 * @package BlaminhorEssentials
 */

// Prevent direct access.
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * HTTPS Redirect module class
 */
class Blaminhor_Essentials_Module_HTTPS_Redirect extends Blaminhor_Essentials_Module {

	/**
	 * Module ID
	 *
	 * @var string
	 */
	protected $id = 'https-redirect';

	/**
	 * Module name
	 *
	 * @var string
	 */
	protected $name = 'HTTPS Redirect';

	/**
	 * Initialize module
	 */
	protected function init() {
		$this->name        = __( 'HTTPS Redirect', 'blaminhor-essentials' );
		$this->description = __( 'Force HTTPS redirection for your site.', 'blaminhor-essentials' );
	}

	/**
	 * Get default settings
	 *
	 * @return array
	 */
	protected function get_default_settings() {
		return array(
			'enabled'           => false, // Disabled by default - user must read warning first.
			'redirect_admin'    => true,
			'fix_mixed_content' => false,
			'hsts_enabled'      => false,
			'hsts_max_age'      => 31536000, // 1 year.
		);
	}

	/**
	 * Register hooks
	 */
	protected function register_hooks() {
		// Admin hooks.
		add_action( 'admin_init', array( $this, 'handle_settings_submission' ) );

		// Only apply redirects if enabled.
		if ( ! $this->get_setting( 'enabled', false ) ) {
			return;
		}

		// Frontend and admin redirect.
		add_action( 'template_redirect', array( $this, 'redirect_to_https' ), 1 );

		// Admin redirect if enabled.
		if ( $this->get_setting( 'redirect_admin', true ) ) {
			add_action( 'admin_init', array( $this, 'redirect_to_https' ), 1 );
			add_action( 'login_init', array( $this, 'redirect_to_https' ), 1 );
		}

		// HSTS header.
		if ( $this->get_setting( 'hsts_enabled', false ) ) {
			add_action( 'send_headers', array( $this, 'send_hsts_header' ) );
		}

		// Fix mixed content in output.
		if ( $this->get_setting( 'fix_mixed_content', false ) ) {
			add_action( 'template_redirect', array( $this, 'start_output_buffer' ), 0 );
		}
	}

	/**
	 * Redirect HTTP to HTTPS
	 */
	public function redirect_to_https() {
		// Skip if already HTTPS.
		if ( is_ssl() ) {
			return;
		}

		// Skip AJAX requests.
		if ( wp_doing_ajax() ) {
			return;
		}

		// Skip CLI.
		if ( defined( 'WP_CLI' ) && WP_CLI ) {
			return;
		}

		// Skip cron.
		if ( wp_doing_cron() ) {
			return;
		}

		// Skip recovery mode URLs (allow HTTP access for recovery).
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Just checking if parameter exists.
		if ( isset( $_GET['be_recovery'] ) || isset( $_GET['ap_recovery'] ) ) {
			return;
		}

		// Build HTTPS URL with proper sanitization.
		$http_host   = isset( $_SERVER['HTTP_HOST'] ) ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_HOST'] ) ) : '';
		$request_uri = isset( $_SERVER['REQUEST_URI'] ) ? esc_url_raw( wp_unslash( $_SERVER['REQUEST_URI'] ) ) : '/';
		$redirect_url = 'https://' . $http_host . $request_uri;

		// Perform redirect (using wp_safe_redirect with allowed_hosts filter).
		// Note: We add current host to allowed hosts temporarily for this redirect.
		add_filter( 'allowed_redirect_hosts', array( $this, 'allow_current_host' ) );
		wp_safe_redirect( $redirect_url, 301 );
		remove_filter( 'allowed_redirect_hosts', array( $this, 'allow_current_host' ) );
		exit;
	}

	/**
	 * Send HSTS header
	 */
	public function send_hsts_header() {
		if ( ! is_ssl() ) {
			return;
		}

		$max_age = absint( $this->get_setting( 'hsts_max_age', 31536000 ) );
		header( 'Strict-Transport-Security: max-age=' . $max_age . '; includeSubDomains; preload' );
	}

	/**
	 * Start output buffering for mixed content fix
	 */
	public function start_output_buffer() {
		if ( is_ssl() ) {
			ob_start( array( $this, 'fix_mixed_content_callback' ) );
		}
	}

	/**
	 * Fix mixed content in HTML output
	 *
	 * @param string $content HTML content.
	 * @return string Fixed content.
	 */
	public function fix_mixed_content_callback( $content ) {
		// Get site URL without protocol.
		$site_url = preg_replace( '#^https?://#', '', home_url() );

		// Replace HTTP with HTTPS for same domain.
		$content = str_replace(
			'http://' . $site_url,
			'https://' . $site_url,
			$content
		);

		// Fix common protocol-relative URLs that might break.
		$content = preg_replace(
			'#(src|href|action)=(["\'])http://#i',
			'$1=$2https://',
			$content
		);

		return $content;
	}

	/**
	 * Allow current host for redirect
	 *
	 * @param array $hosts Allowed hosts.
	 * @return array
	 */
	public function allow_current_host( $hosts ) {
		$current_host = isset( $_SERVER['HTTP_HOST'] ) ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_HOST'] ) ) : '';
		if ( ! empty( $current_host ) && ! in_array( $current_host, $hosts, true ) ) {
			$hosts[] = $current_host;
		}
		return $hosts;
	}

	/**
	 * Check if SSL is available
	 *
	 * @return bool
	 */
	private function check_ssl_available() {
		// Check if we're already on HTTPS.
		if ( is_ssl() ) {
			return true;
		}

		// Try to make a request to HTTPS version.
		$https_url = str_replace( 'http://', 'https://', home_url() );

		$response = wp_remote_head(
			$https_url,
			array(
				'timeout'   => 5,
				'sslverify' => true,
			)
		);

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

		$response_code = wp_remote_retrieve_response_code( $response );
		return $response_code >= 200 && $response_code < 400;
	}

	/**
	 * Check if Fatal Error Recovery module is active
	 *
	 * @return bool
	 */
	private function is_recovery_module_active() {
		$active_modules = get_option( 'blaminhor_essentials_active_modules', array() );
		return in_array( 'fatal-error-recovery', $active_modules, true );
	}

	/**
	 * Render settings page
	 */
	public function render_settings_page() {
		$enabled           = $this->get_setting( 'enabled', false );
		$redirect_admin    = $this->get_setting( 'redirect_admin', true );
		$fix_mixed_content = $this->get_setting( 'fix_mixed_content', false );
		$hsts_enabled      = $this->get_setting( 'hsts_enabled', false );
		$hsts_max_age      = $this->get_setting( 'hsts_max_age', 31536000 );
		$is_ssl            = is_ssl();
		$ssl_available     = $is_ssl || $this->check_ssl_available();
		$recovery_active   = $this->is_recovery_module_active();
		?>
		<div class="wrap blaminhor-essentials-wrap">
			<div class="blaminhor-essentials-header">
				<h1><?php esc_html_e( 'HTTPS Redirect', 'blaminhor-essentials' ); ?></h1>
				<p class="blaminhor-essentials-tagline"><?php esc_html_e( 'Force HTTPS redirection for your site.', 'blaminhor-essentials' ); ?></p>
			</div>

			<div class="blaminhor-essentials-card">
				<?php // Warning about HTTPS redirect risks. ?>
				<div class="blaminhor-essentials-notice warning">
					<strong><span class="dashicons dashicons-warning ap-icon-mr"></span><?php esc_html_e( 'Warning', 'blaminhor-essentials' ); ?></strong>
					<p>
						<?php esc_html_e( 'Enabling HTTPS redirection may lock you out of your site if SSL is not properly configured. If you cannot access your site after enabling this feature, you can disable the plugin by renaming its folder via FTP/SFTP.', 'blaminhor-essentials' ); ?>
					</p>
					<?php if ( ! $recovery_active ) : ?>
						<p>
							<strong><?php esc_html_e( 'Recommendation:', 'blaminhor-essentials' ); ?></strong>
							<?php
							printf(
								/* translators: %s: Link to modules page */
								esc_html__( 'Enable the %s module before activating HTTPS redirect. It provides a recovery URL that works even if HTTPS fails.', 'blaminhor-essentials' ),
								'<a href="' . esc_url( admin_url( 'admin.php?page=blaminhor-essentials' ) ) . '"><strong>' . esc_html__( 'Fatal Error Recovery', 'blaminhor-essentials' ) . '</strong></a>'
							);
							?>
						</p>
					<?php else : ?>
						<p style="color: #1e4620;">
							<span class="dashicons dashicons-yes-alt ap-text-success"></span>
							<?php
							printf(
								/* translators: %s: Link to recovery module */
								esc_html__( 'The %s module is active. Save your recovery URL before enabling HTTPS redirect.', 'blaminhor-essentials' ),
								'<a href="' . esc_url( admin_url( 'admin.php?page=blaminhor-essentials-fatal-error-recovery' ) ) . '">' . esc_html__( 'Fatal Error Recovery', 'blaminhor-essentials' ) . '</a>'
							);
							?>
						</p>
					<?php endif; ?>
				</div>

				<?php if ( $is_ssl ) : ?>
					<div class="ap-status-banner ap-status-success">
						<span class="dashicons dashicons-lock"></span>
						<span><?php esc_html_e( 'Your site is currently being accessed via HTTPS.', 'blaminhor-essentials' ); ?></span>
					</div>
				<?php elseif ( ! $ssl_available ) : ?>
					<div class="ap-status-banner ap-status-warning">
						<span class="dashicons dashicons-warning"></span>
						<span><?php esc_html_e( 'SSL certificate not detected. Please install an SSL certificate before enabling HTTPS redirection.', 'blaminhor-essentials' ); ?></span>
					</div>
				<?php else : ?>
					<div class="ap-status-banner ap-status-info">
						<span class="dashicons dashicons-info"></span>
						<span><?php esc_html_e( 'SSL certificate detected. You can enable HTTPS redirection.', 'blaminhor-essentials' ); ?></span>
					</div>
				<?php endif; ?>

				<div class="ap-important-notes">
					<h3><?php esc_html_e( 'Important Notes', 'blaminhor-essentials' ); ?></h3>
					<ul>
						<li><?php esc_html_e( 'Make sure you have a valid SSL certificate installed before enabling HTTPS redirect.', 'blaminhor-essentials' ); ?></li>
						<li><?php
							printf(
								/* translators: %s: Link to Settings > General page */
								esc_html__( 'Update your WordPress Address (URL) and Site Address (URL) in %s to use HTTPS.', 'blaminhor-essentials' ),
								'<a href="' . esc_url( admin_url( 'options-general.php' ) ) . '">' . esc_html__( 'Settings > General', 'blaminhor-essentials' ) . '</a>'
							);
						?></li>
						<li><?php esc_html_e( 'After enabling, test your site thoroughly to ensure all resources load correctly.', 'blaminhor-essentials' ); ?></li>
						<li><?php esc_html_e( 'If you get locked out, you can disable this module by renaming the plugin folder via FTP/SFTP.', 'blaminhor-essentials' ); ?></li>
					</ul>
				</div>

				<form method="post">
					<?php $this->render_nonce_field(); ?>

					<h3><?php esc_html_e( 'Redirection Settings', 'blaminhor-essentials' ); ?></h3>

					<table class="form-table">
						<tr>
							<th scope="row"><?php esc_html_e( 'Enable HTTPS Redirect', 'blaminhor-essentials' ); ?></th>
							<td>
								<label>
									<input type="checkbox" name="enabled" value="1" <?php checked( $enabled ); ?>>
									<?php esc_html_e( 'Redirect all HTTP requests to HTTPS', 'blaminhor-essentials' ); ?>
								</label>
								<p class="description"><?php esc_html_e( 'Visitors will be automatically redirected to the secure HTTPS version of your site.', 'blaminhor-essentials' ); ?></p>
							</td>
						</tr>
						<tr>
							<th scope="row"><?php esc_html_e( 'Admin & Login', 'blaminhor-essentials' ); ?></th>
							<td>
								<label>
									<input type="checkbox" name="redirect_admin" value="1" <?php checked( $redirect_admin ); ?>>
									<?php esc_html_e( 'Also redirect admin area and login page', 'blaminhor-essentials' ); ?>
								</label>
								<p class="description"><?php esc_html_e( 'Recommended for security. Forces HTTPS on wp-admin and wp-login.php.', 'blaminhor-essentials' ); ?></p>
							</td>
						</tr>
					</table>

					<hr>

					<h3><?php esc_html_e( 'Advanced Options', 'blaminhor-essentials' ); ?></h3>

					<table class="form-table">
						<tr>
							<th scope="row"><?php esc_html_e( 'Fix Mixed Content', 'blaminhor-essentials' ); ?></th>
							<td>
								<label>
									<input type="checkbox" name="fix_mixed_content" value="1" <?php checked( $fix_mixed_content ); ?>>
									<?php esc_html_e( 'Automatically fix HTTP URLs in page output', 'blaminhor-essentials' ); ?>
								</label>
								<p class="description"><?php esc_html_e( 'Replaces HTTP URLs with HTTPS in the HTML output. Use only if you have mixed content warnings.', 'blaminhor-essentials' ); ?></p>
							</td>
						</tr>
						<tr>
							<th scope="row"><?php esc_html_e( 'HSTS Header', 'blaminhor-essentials' ); ?></th>
							<td>
								<label>
									<input type="checkbox" name="hsts_enabled" value="1" <?php checked( $hsts_enabled ); ?>>
									<?php esc_html_e( 'Enable HTTP Strict Transport Security (HSTS)', 'blaminhor-essentials' ); ?>
								</label>
								<p class="description"><?php esc_html_e( 'Tells browsers to always use HTTPS for your site. Improves security but cannot be easily undone.', 'blaminhor-essentials' ); ?></p>
								<?php if ( $hsts_enabled ) : ?>
									<p class="description ap-desc-danger-bold">
										<?php esc_html_e( 'Warning: Once HSTS is cached by browsers, your site must remain on HTTPS. Disabling this setting will not immediately undo the browser cache.', 'blaminhor-essentials' ); ?>
									</p>
								<?php endif; ?>
							</td>
						</tr>
						<?php if ( $hsts_enabled ) : ?>
						<tr>
							<th scope="row">
								<label for="hsts_max_age"><?php esc_html_e( 'HSTS Max Age', 'blaminhor-essentials' ); ?></label>
							</th>
							<td>
								<select name="hsts_max_age" id="hsts_max_age">
									<option value="86400" <?php selected( $hsts_max_age, 86400 ); ?>><?php esc_html_e( '1 day (testing)', 'blaminhor-essentials' ); ?></option>
									<option value="604800" <?php selected( $hsts_max_age, 604800 ); ?>><?php esc_html_e( '1 week', 'blaminhor-essentials' ); ?></option>
									<option value="2592000" <?php selected( $hsts_max_age, 2592000 ); ?>><?php esc_html_e( '1 month', 'blaminhor-essentials' ); ?></option>
									<option value="31536000" <?php selected( $hsts_max_age, 31536000 ); ?>><?php esc_html_e( '1 year (recommended)', 'blaminhor-essentials' ); ?></option>
									<option value="63072000" <?php selected( $hsts_max_age, 63072000 ); ?>><?php esc_html_e( '2 years', 'blaminhor-essentials' ); ?></option>
								</select>
								<p class="description"><?php esc_html_e( 'How long browsers should remember to use HTTPS.', 'blaminhor-essentials' ); ?></p>
							</td>
						</tr>
						<?php endif; ?>
					</table>

					<p class="submit">
						<button type="submit" class="button button-primary"><?php esc_html_e( 'Save Settings', 'blaminhor-essentials' ); ?></button>
					</p>
				</form>
			</div>
		</div>
		<?php
	}

	/**
	 * Process settings
	 *
	 * @param array $data Form data.
	 */
	protected function process_settings( $data ) {
		$settings = array(
			'enabled'           => isset( $data['enabled'] ),
			'redirect_admin'    => isset( $data['redirect_admin'] ),
			'fix_mixed_content' => isset( $data['fix_mixed_content'] ),
			'hsts_enabled'      => isset( $data['hsts_enabled'] ),
			'hsts_max_age'      => isset( $data['hsts_max_age'] ) ? absint( $data['hsts_max_age'] ) : 31536000,
		);

		$this->save_settings( $settings );

		add_action( 'admin_notices', function () {
			blaminhor_essentials_admin_notice( __( 'Settings saved.', 'blaminhor-essentials' ), 'success' );
		} );
	}
}
