<?php
namespace WPUltimateSecurity\UltimateSecurity\Modules\Authentication\TwoFactor\Http;

use WPUltimateSecurity\UltimateSecurity\Modules\Authentication\TwoFactor\Providers\EmailProvider;
use WPUltimateSecurity\UltimateSecurity\Modules\Authentication\TwoFactor\Providers\TOTPProvider;
use WPUltimateSecurity\UltimateSecurity\Modules\Authentication\TwoFactor\Providers\HOTPProvider;
use WPUltimateSecurity\UltimateSecurity\Modules\Authentication\TwoFactor\Services\RateLimitService;
use WPUltimateSecurity\UltimateSecurity\Modules\Authentication\TwoFactor\Services\SimpleBackupCodeService;
use WPUltimateSecurity\UltimateSecurity\Modules\Authentication\TwoFactor\Services\TokenService;
use WPUltimateSecurity\UltimateSecurity\Modules\Authentication\TwoFactor\Services\TrustedDeviceService;
use WPUltimateSecurity\UltimateSecurity\Modules\Authentication\TwoFactor\Helpers\DeviceFingerprint;
use WPUltimateSecurity\UltimateSecurity\Support\Helpers\Utils;
use WPUltimateSecurity\UltimateSecurity\Support\Helpers\DateHelper;
use WPUltimateSecurity\UltimateSecurity\Support\Validation\ProFeatureMiddleware;
use WPUltimateSecurity\UltimateSecurity\Support\Validation\ProValidation;

/**
 * Verification Handler for 2FA
 *
 * Handles the 2FA verification page and code verification process
 * Uses token-based authentication similar to Two Factor by WordPress.org
 * and WP 2FA by Melapress
 *
 * Key differences from cookie-based approach:
 * - Verification happens on wp-login.php with action=ultimate_security_2fa
 * - User ID and auth token are passed via hidden form fields
 * - No cookies are used for user identification
 */
class VerificationHandler
{
	/**
	 * Handle 2FA verification page display and submission on wp-login.php
	 *
	 * This is called on login_init to detect and handle 2FA without query parameters
	 */
	public static function handle_verification_page()
	{
		global $pagenow;
		// var_dump($pagenow);
		
		// Only handle on wp-login.php
		if ($pagenow !== 'wp-login.php' && $pagenow !== 'index.php') {
			return;
		}

		// Check if this is a POST submission (2FA form already submitted)
		if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['ultimate_security_2fa_code'])) {
			$verification_data = self::get_verification_data_from_post();
		} else {
			// Check for pending 2FA
			$verification_data = self::detect_pending_2fa();
		}

		if (!$verification_data) {
			return; // No 2FA pending, continue normal login flow
		}

		$user_id = $verification_data['user_id'];
		$token = $verification_data['token'];
		$provider = $verification_data['provider'];

		// Validate the token
		if (!TokenService::validate_auth_token($user_id, $token)) {
			// Invalid token - clean up markers and redirect to login with error
			delete_user_meta($user_id, 'ultimate_security_2fa_pending');
			delete_user_meta($user_id, '_ultimate_security_2fa_login_pending');
			TokenService::clear_auth_token($user_id);
			wp_safe_redirect(add_query_arg('login_error', 'session_expired', wp_login_url()));
			exit;
		}

		// Check if user exists
		$user = get_user_by('id', $user_id);
		if (!$user) {
			wp_safe_redirect(wp_login_url());
			exit;
		}

		// Check 2FA pending flag
		if (!get_user_meta($user_id, 'ultimate_security_2fa_pending', true)) {
			// Clean up any stray markers
			delete_user_meta($user_id, '_ultimate_security_2fa_login_pending');
			wp_safe_redirect(wp_login_url());
			exit;
		}

		// Initialize error variable
		$GLOBALS['ultimate_security_otp_error'] = '';

		// Handle form submission (POST request with verification code)
		if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['ultimate_security_2fa_code'])) {
			// Verify nonce
			if (!isset($_POST['ultimate_security_login_form_field']) ||
				!wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['ultimate_security_login_form_field'])), 'ultimate_security_login_form_action')) {
				$GLOBALS['ultimate_security_otp_error'] = __('Security verification failed. Please try again.', 'ultimate-security');
			} else {
				// Validate token from hidden form field
				$post_user_id = isset($_POST['wp-auth-id']) ? absint($_POST['wp-auth-id']) : 0;
				$post_token = isset($_POST['wp-auth-nonce']) ? sanitize_text_field(wp_unslash($_POST['wp-auth-nonce'])) : '';

				if ($post_user_id !== $user_id || !TokenService::validate_auth_token($post_user_id, $post_token)) {
					$GLOBALS['ultimate_security_otp_error'] = __('Session expired. Please log in again.', 'ultimate-security');
				} else {
					self::process_verification_submission($user_id, $user, $token);
				}
			}
		}

		// Display the verification form on wp-login.php
		self::display_verification_form($user_id, $user, $provider, $token);
		exit;
	}

	/**
	 * Detect pending 2FA without query parameters
	 *
	 * @return array|false Array with user_id, token, provider or false
	 */
	private static function detect_pending_2fa()
	{
		// First try to find pending 2FA by scanning transients 
		// This preserves the original token for form consistency across page refreshes
		global $wpdb;
		$transient_prefix = '_transient_ultimate_security_2fa_session_';
		$transients = $wpdb->get_col($wpdb->prepare(
			"SELECT option_name FROM $wpdb->options WHERE option_name LIKE %s AND option_value IS NOT NULL",
			$transient_prefix . '%'
		));

		foreach ($transients as $transient_name) {
			$session_data = get_transient(str_replace('_transient_', '', $transient_name));
			
			if ($session_data && is_array($session_data)) {
				$user_id = $session_data['user_id'] ?? 0;
				$token = $session_data['token'] ?? '';
				$provider = $session_data['provider'] ?? '';
				$created_at = $session_data['created_at'] ?? 0;
				
				// Validate the session data
				if ($user_id && $token && ($created_at > (time() - 30 * MINUTE_IN_SECONDS))) {
					// Verify user still has pending 2FA
					$pending = get_user_meta($user_id, 'ultimate_security_2fa_pending', true);
					if ($pending) {
						// Verify the token is still valid - catch exceptions for old/mismatched tokens
						try {
							if (TokenService::validate_auth_token($user_id, $token)) {
								// Check if this session was created very recently (within 2 minutes)
								// This prevents redirecting to 2FA form from old/sessions that should be expired
								$session_age = time() - $created_at;
								if ($session_age > 2 * MINUTE_IN_SECONDS && $_SERVER['REQUEST_METHOD'] === 'GET') {
									// Session is older than 2 minutes and this is a GET request
									// This is likely a stale session from a previous login attempt
									// Clean it up and continue searching
									delete_user_meta($user_id, 'ultimate_security_2fa_pending');
									delete_transient(str_replace('_transient_', '', $transient_name));
									continue;
								}
								
								// Don't delete the transient - keep it for page refreshes
								// Only delete the persistent marker since we found valid data
								delete_user_meta($user_id, '_ultimate_security_2fa_login_pending');
								
								return [
									'user_id' => $user_id,
									'token' => $token,
									'provider' => $provider,
								];
							}
						} catch (\WPUltimateSecurity\UltimateSecurity\Support\Exceptions\AuthenticationException $e) {
							// Token is invalid or expired - skip this transient and continue searching
							continue;
						}
					}
				}
			}
		}

		// Fallback: try to find pending 2FA by checking user meta markers
		// This is used when transients are expired but user meta still exists
		$prefix = '_ultimate_security_2fa_login_pending';
		$pending_users = $wpdb->get_col($wpdb->prepare(
			"SELECT user_id FROM $wpdb->usermeta WHERE meta_key = %s",
			$prefix
		));

		foreach ($pending_users as $user_id) {
			$user_id = absint($user_id);
			
			// Verify user still has pending 2FA
			$pending = get_user_meta($user_id, 'ultimate_security_2fa_pending', true);
			if ($pending) {
				// Check if user has a valid auth token
				if (TokenService::has_pending_token($user_id)) {
					// Get the 2FA provider for this user
					$provider = LoginHandler::get_user_2fa_status($user_id);
					
					if ($provider) {
						// Generate a new token only when transients are unavailable
						// This maintains the token in user meta for subsequent requests
						$new_token = TokenService::generate_auth_token($user_id);
						
						// Create a new transient with the fresh token
						$session_key = 'ultimate_security_2fa_session_' . wp_hash($user_id . $new_token . time());
						set_transient($session_key, [
							'user_id' => $user_id,
							'token' => $new_token,
							'provider' => $provider,
							'created_at' => time(),
						], 300);
						
						// Clean up the pending marker
						delete_user_meta($user_id, '_ultimate_security_2fa_login_pending');
						
						return [
							'user_id' => $user_id,
							'token' => $new_token,
							'provider' => $provider,
						];
					}
				} else {
					// Clean up expired markers
					delete_user_meta($user_id, 'ultimate_security_2fa_pending');
					delete_user_meta($user_id, '_ultimate_security_2fa_login_pending');
				}
			} else {
				// Clean up stray markers
				delete_user_meta($user_id, '_ultimate_security_2fa_login_pending');
			}
		}

		return false;
	}

	/**
	 * Get verification data from POST data
	 *
	 * @return array|false Array with user_id, token, provider or false
	 */
	private static function get_verification_data_from_post()
	{
		if (isset($_POST['wp-auth-id']) && isset($_POST['wp-auth-nonce'])) {
			return [
				'user_id' => absint($_POST['wp-auth-id']),
				'token' => sanitize_text_field(wp_unslash($_POST['wp-auth-nonce'])),
				'provider' => isset($_POST['provider']) ? sanitize_text_field(wp_unslash($_POST['provider'])) : '',
			];
		}

		return false;
	}

	/**
	 * Display the 2FA verification form on wp-login.php
	 *
	 * @param int $user_id User ID
	 * @param \WP_User $user User object
	 * @param string $provider 2FA provider
	 * @param string $token Auth token
	 */
	private static function display_verification_form($user_id, $user, $provider, $token)
	{
		$initial_cooldown_remaining = 0;
		// Get error message
		$error = $GLOBALS['ultimate_security_otp_error'] ?? '';

		// Get provider display name
		$provider_name = self::get_provider_display_name($provider);

		// Load WordPress login header
		login_header(
			__('Two-Factor Authentication', 'ultimate-security'),
			$error ? '<div id="login_error" class="notice notice-error">' . esc_html($error) . '</div>' : ''
		);
		// Build the verification form
		?>
		<form name="2fa_form" id="2fa_form" action="<?php echo esc_url(wp_login_url()); ?>" method="post" autocomplete="off">
			<div class="user-pass-wrap">
				<p class="two-factor-prompt">
					<?php
					if ($provider === 'email') {
						printf(
							/* translators: %s: user email */
							esc_html__('A verification code has been sent to %s', 'ultimate-security'),
							'<strong>' . esc_html(self::mask_email($user->user_email)) . '</strong>'
						);
					} else {
						echo esc_html__('Enter the verification code from your authenticator app', 'ultimate-security');
					}
					?>
				</p>
				<label for="ultimate_security_2fa_code"><?php echo esc_html__('Verification Code', 'ultimate-security'); ?></label>
				<input type="text" name="ultimate_security_2fa_code" id="ultimate_security_2fa_code"
					   class="input" size="20" autocomplete="one-time-code" inputmode="numeric"
					   pattern="[0-9]*" maxlength="<?php echo ($provider === 'backup_code') ? '10' : '6'; ?>"
					   autofocus required />
			</div>

			<?php
			if(ProValidation::ultimate_security_is_pro()) {
				// Backup codes option (works with both Pro and Free versions)
				$backup_count = 0;
				if (class_exists('\WPUltimateSecurity\UltimateSecurityPro\Modules\Authentication\TwoFactor\Services\BackupCodeService')) {
					$backup_count = \WPUltimateSecurity\UltimateSecurityPro\Modules\Authentication\TwoFactor\Services\BackupCodeService::get_remaining_count($user_id);
				} else {
					$backup_count = SimpleBackupCodeService::get_remaining_count($user_id);
				}
				if ($backup_count > 0) {
					?>
					<p class="backup-code-option">
						<label>
							<input type="checkbox" name="use_backup_code" id="use_backup_code" value="1" />
							<?php echo esc_html__('Use backup code instead', 'ultimate-security'); ?>
							<span class="backup-count">(<?php echo esc_html($backup_count); ?> <?php echo esc_html__('remaining', 'ultimate-security'); ?>)</span>
						</label>
					</p>
					<?php
				}
			}
			?>

			<?php
			// Trusted device checkbox (Pro feature)
			if (ProFeatureMiddleware::hasProFeature('trusted_devices') && TrustedDeviceService::show_remember_checkbox()) {
				$settings = TrustedDeviceService::get_settings();
				$trust_duration = (int) ($settings['trust_duration'] ?? 30);
				?>
				<p class="trusted-device-option">
					<label>
						<input type="checkbox" name="remember_device" id="remember_device" value="1" />
						<?php
						printf(
							/* translators: %d: Number of days */
							esc_html__('Remember this device for %d days', 'ultimate-security'),
							$trust_duration
						);
						?>
					</label>
					<span class="trusted-device-info">
						<?php echo esc_html__('Skip 2FA on future logins from this browser.', 'ultimate-security'); ?>
					</span>
				</p>
				<?php
			}
			?>

			<?php
			// Hidden fields for token-based authentication (like Two Factor plugin)
			echo TokenService::get_hidden_fields($user_id, $provider, $token);
			wp_nonce_field('ultimate_security_login_form_action', 'ultimate_security_login_form_field');
			?>

			<p class="submit">
				<input type="submit" name="wp-submit" id="wp-submit"
					   class="button button-primary button-large"
					   value="<?php esc_attr_e('Verify', 'ultimate-security'); ?>" />
			</p>

			<?php if ($provider === 'email') : ?>
			<p class="resend-code">
				<a href="#" id="resend-code-link" data-nonce="<?php echo esc_attr(wp_create_nonce('ultimate_security_resend_2fa_code')); ?>"
				   data-user-id="<?php echo esc_attr($user_id); ?>" data-token="<?php echo esc_attr($token); ?>"
				   <?php echo $initial_cooldown_remaining > 0 ? 'style="display: none;"' : ''; ?>>
					<?php echo esc_html__('Resend verification code', 'ultimate-security'); ?>
				</a>
				<span id="resend-countdown" <?php echo $initial_cooldown_remaining > 0 ? 'style="display: inline;"' : 'style="display: none;"'; ?>></span>
			</p>
			<?php endif; ?>

			<p class="back-to-login">
				<a href="<?php echo esc_url(wp_login_url()); ?>">
					<?php echo esc_html__('&larr; Back to login', 'ultimate-security'); ?>
				</a>
			</p>
		</form>

		<style>
			.two-factor-prompt {
				margin-bottom: 16px;
				padding: 12px;
				background: #f0f6fc;
				border-left: 4px solid #0073aa;
				color: #1e1e1e;
			}
			.backup-code-option {
				margin: 16px 0;
			}
			.backup-count {
				color: #666;
				font-size: 12px;
			}
			.trusted-device-option {
				margin: 16px 0;
				padding: 12px;
				background: #f7f7f7;
				border-radius: 4px;
			}
			.trusted-device-option label {
				display: flex;
				align-items: center;
				gap: 8px;
				cursor: pointer;
			}
			.trusted-device-info {
				display: block;
				margin-top: 4px;
				margin-left: 24px;
				color: #666;
				font-size: 12px;
			}
			.resend-code {
				text-align: center;
				margin-top: 16px;
			}
			#resend-countdown {
				color: #666;
				font-size: 12px;
			}
			.back-to-login {
				text-align: center;
			}
			#ultimate_security_2fa_code {
				font-size: 24px;
				text-align: center;
				letter-spacing: 8px;
				font-family: monospace;
			}
		</style>

		<script>
		(function() {
			// Resend code functionality
			var resendLink = document.getElementById('resend-code-link');
			var countdown = document.getElementById('resend-countdown');
			var cooldownTime = 60;
			var initialCooldown = <?php echo (int) $initial_cooldown_remaining; ?>;

			// Handle initial cooldown state
			if (initialCooldown > 0) {
				startCountdown(initialCooldown);
			}

			if (resendLink) {
				resendLink.addEventListener('click', function(e) {
					e.preventDefault();

					var nonce = this.getAttribute('data-nonce');
					var userId = this.getAttribute('data-user-id');
					var token = this.getAttribute('data-token');

					// Disable link
					resendLink.style.display = 'none';
					countdown.style.display = 'inline';

					// Send AJAX request
					var xhr = new XMLHttpRequest();
					xhr.open('POST', '<?php echo esc_js(admin_url('admin-ajax.php')); ?>', true);
					xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
					xhr.onreadystatechange = function() {
						if (xhr.readyState === 4) {
							if (xhr.status === 200) {
								try {
									var response = JSON.parse(xhr.responseText);
									if (response.success) {
										countdown.textContent = '<?php echo esc_js(__('Code sent! Check your email.', 'ultimate-security')); ?>';
									} else {
										var errorMsg = (response.data && response.data.error_message) ? response.data.error_message : '<?php echo esc_js(__('Failed to send code.', 'ultimate-security')); ?>';
										countdown.textContent = errorMsg;
									}
								} catch (e) {
									countdown.textContent = '<?php echo esc_js(__('Failed to send code.', 'ultimate-security')); ?>';
								}
							}
						}
					};
					xhr.send('action=ultimate_security_resend_2fa_code&nonce=' + nonce + '&user_id=' + userId + '&token=' + token);

					// Start countdown
					startCountdown(cooldownTime);
				});
			}

			function startCountdown(seconds) {
				var remaining = seconds;
				var interval = setInterval(function() {
					remaining--;
					if (remaining <= 0) {
						clearInterval(interval);
						resendLink.style.display = 'inline';
						countdown.style.display = 'none';
					} else {
						countdown.textContent = '<?php echo esc_js(__('Resend available in', 'ultimate-security')); ?> ' + remaining + 's';
					}
				}, 1000);
			}

			// Handle backup code checkbox - update input field attributes
			var useBackupCodeCheckbox = document.getElementById('use_backup_code');
			var codeInput = document.getElementById('ultimate_security_2fa_code');

			if (useBackupCodeCheckbox && codeInput) {
				var originalMaxLength = codeInput.getAttribute('maxlength') || '6';
				var originalPattern = codeInput.getAttribute('pattern') || '[0-9]*';
				var originalInputmode = codeInput.getAttribute('inputmode') || 'numeric';

				useBackupCodeCheckbox.addEventListener('change', function() {
					if (this.checked) {
						codeInput.setAttribute('maxlength', '10');
						codeInput.setAttribute('pattern', '[A-Za-z0-9]*');
						codeInput.setAttribute('inputmode', 'text');
						codeInput.setAttribute('placeholder', '<?php echo esc_js(__('Enter code', 'ultimate-security')); ?>');
					} else {
						codeInput.setAttribute('maxlength', originalMaxLength);
						codeInput.setAttribute('pattern', originalPattern);
						codeInput.setAttribute('inputmode', originalInputmode);
						codeInput.removeAttribute('placeholder');
					}
				});
			}

			// Auto-focus the code input
			if (codeInput) {
				codeInput.focus();
			}
		})();
		</script>
		<?php

		login_footer();
	}

	/**
	 * Get provider display name
	 *
	 * @param string $provider Provider key
	 * @return string Display name
	 */
	private static function get_provider_display_name($provider)
	{
		$names = [
			'email' => __('Email', 'ultimate-security'),
			'totp' => __('Authenticator App (TOTP)', 'ultimate-security'),
			'hotp' => __('Authenticator App (HOTP)', 'ultimate-security'),
			'sms' => __('SMS', 'ultimate-security'),
		];

		return $names[$provider] ?? $provider;
	}

	/**
	 * Mask email address for privacy
	 *
	 * @param string $email Email address
	 * @return string Masked email
	 */
	private static function mask_email($email)
	{
		$parts = explode('@', $email);
		if (count($parts) !== 2) {
			return $email;
		}

		$local = $parts[0];
		$domain = $parts[1];

		$local_len = strlen($local);
		if ($local_len <= 2) {
			$masked_local = str_repeat('*', $local_len);
		} else {
			$masked_local = substr($local, 0, 1) . str_repeat('*', $local_len - 2) . substr($local, -1);
		}

		return $masked_local . '@' . $domain;
	}

	/**
	 * Process verification form submission
	 *
	 * @param int $user_id User ID
	 * @param \WP_User $user User object
	 * @param string $token Auth token
	 */
	protected static function process_verification_submission($user_id, $user, $token)
	{
		// NOTE: Don't clean up transients here - they're needed for page refresh/retry
		// Transients will be cleaned up in finalize_successful_verification() after successful 2FA

		// Check rate limiting
		$rate_limit = RateLimitService::check_rate_limit($user_id);
		if (!$rate_limit['allowed']) {
			$GLOBALS['ultimate_security_otp_error'] = $rate_limit['message'];

			// Fire action for SimpleEventLogger and other listeners
			do_action('ultimate_security_user_locked_out', $user_id, '2fa_failed_attempts', $rate_limit['lockout_duration'] ?? 300);

			self::send_notification($user_id, '2fa_lockout');
			return;
		}

		$entered_code = isset($_POST['ultimate_security_2fa_code']) ? sanitize_text_field(wp_unslash($_POST['ultimate_security_2fa_code'])) : '';

		if (empty($entered_code)) {
			$GLOBALS['ultimate_security_otp_error'] = __('Please enter a verification code.', 'ultimate-security');
			return;
		}

		$twofa_status = LoginHandler::get_user_2fa_status($user_id);
		$is_verified = false;

		// Check if code has expired (for email 2FA)
		if ($twofa_status === 'email') {
			$code_expires = get_user_meta($user_id, 'ultimate_security_2fa_code_expires', true);
			if ($code_expires && time() > $code_expires) {
				$GLOBALS['ultimate_security_otp_error'] = __('Verification code has expired. Please request a new code.', 'ultimate-security');
				delete_user_meta($user_id, 'ultimate_security_2fa_code');
				delete_user_meta($user_id, 'ultimate_security_2fa_code_expires');
				delete_transient('2fa_code_generation_' . $user_id);
				return;
			}
		}

		// Check if using backup code
		if (isset($_POST['use_backup_code']) && $_POST['use_backup_code'] === '1') {
			// Determine which backup code service to use (Pro or Simple)
			$has_pro_backup = class_exists('\WPUltimateSecurity\UltimateSecurityPro\Modules\Authentication\TwoFactor\Services\BackupCodeService');

			// Get remaining codes count
			if ($has_pro_backup) {
				$backup_codes_count = \WPUltimateSecurity\UltimateSecurityPro\Modules\Authentication\TwoFactor\Services\BackupCodeService::get_remaining_count($user_id);
			} else {
				$backup_codes_count = SimpleBackupCodeService::get_remaining_count($user_id);
			}

			if ($backup_codes_count === 0) {
				$GLOBALS['ultimate_security_otp_error'] = __('No backup codes available. Please use your regular 2FA method or contact an administrator.', 'ultimate-security');
				return;
			}

			// Verify backup code
			if ($has_pro_backup) {
				$is_verified = \WPUltimateSecurity\UltimateSecurityPro\Modules\Authentication\TwoFactor\Services\BackupCodeService::verify_code($user_id, $entered_code);
			} else {
				$is_verified = SimpleBackupCodeService::verify_code($user_id, $entered_code);
			}

			if ($is_verified) {
				// Get remaining codes after successful verification
				if ($has_pro_backup) {
					$remaining_codes = \WPUltimateSecurity\UltimateSecurityPro\Modules\Authentication\TwoFactor\Services\BackupCodeService::get_remaining_count($user_id);
				} else {
					$remaining_codes = SimpleBackupCodeService::get_remaining_count($user_id);
				}

				// Pro enhanced logging
				if (class_exists('\WPUltimateSecurity\UltimateSecurityPro\Modules\Authentication\TwoFactor\Storage\LogRepository')) {
					\WPUltimateSecurity\UltimateSecurityPro\Modules\Authentication\TwoFactor\Storage\LogRepository::log_backup_code_used($user_id, $remaining_codes);

					if ($remaining_codes <= 2) {
						$options = Utils::ultimate_security_get_option();
						if (!empty($options['security']['2fa_authentication']['audit_logs']['enable'])) {
							\WPUltimateSecurity\UltimateSecurityPro\Modules\Authentication\TwoFactor\Storage\LogRepository::log_event($user_id, '2fa_backup_codes_low', [
								'remaining_codes' => $remaining_codes,
								'timestamp' => DateHelper::now()
							]);
						}
					}
				}

				self::finalize_successful_verification($user_id, $user, 'backup_code');
			} else {
				RateLimitService::record_failed_attempt($user_id);

				// Fire action for SimpleEventLogger and other listeners
				do_action('ultimate_security_2fa_failed', $user_id, 'backup_code');

				// Log failed backup code attempt (Pro enhanced logging)
				if (class_exists('\WPUltimateSecurity\UltimateSecurityPro\Modules\Authentication\TwoFactor\Storage\LogRepository')) {
					\WPUltimateSecurity\UltimateSecurityPro\Modules\Authentication\TwoFactor\Storage\LogRepository::log_verification_attempt($user_id, 'backup_code', false);
				}

				$GLOBALS['ultimate_security_otp_error'] = __('Invalid backup code. Please check your code and try again.', 'ultimate-security');
			}
		} else {
			// Regular 2FA verification
			$is_verified = self::verify_code($user_id, $twofa_status, $entered_code);

			if ($is_verified) {
				self::finalize_successful_verification($user_id, $user, $twofa_status);
			} else {
				RateLimitService::record_failed_attempt($user_id);

				// Fire action for SimpleEventLogger and other listeners
				do_action('ultimate_security_2fa_failed', $user_id, $twofa_status);

				// Log failed verification attempt (Pro enhanced logging)
				if (class_exists('\WPUltimateSecurity\UltimateSecurityPro\Modules\Authentication\TwoFactor\Storage\LogRepository')) {
					\WPUltimateSecurity\UltimateSecurityPro\Modules\Authentication\TwoFactor\Storage\LogRepository::log_verification_attempt($user_id, $twofa_status, false);
				}

				$GLOBALS['ultimate_security_otp_error'] = __('Invalid verification code. Please try again.', 'ultimate-security');
			}
		}
	}

	/**
	 * Verify code based on 2FA method
	 *
	 * @param int $user_id User ID
	 * @param string $method 2FA method (email, totp, hotp)
	 * @param string $code Entered code
	 * @return bool True if valid
	 */
	protected static function verify_code($user_id, $method, $code)
	{
		switch ($method) {
			case 'email':
				return EmailProvider::verify_code($user_id, $code);
			case 'totp':
				return TOTPProvider::verify_code($user_id, $code);
			case 'hotp':
				return HOTPProvider::verify_code_with_window($user_id, $code, 10);
			case 'sms':
				// Pro provider: SMS Authentication
				if (class_exists('\WPUltimateSecurity\UltimateSecurityPro\Modules\Authentication\Authentication2FASMS')) {
					return \WPUltimateSecurity\UltimateSecurityPro\Modules\Authentication\Authentication2FASMS::verify_sms_code($user_id, $code);
				}
				return false;
			default:
				return false;
		}
	}

	/**
	 * Finalize successful verification and log user in
	 *
	 * @param int $user_id User ID
	 * @param \WP_User $user User object
	 * @param string $method 2FA method used
	 */
	protected static function finalize_successful_verification($user_id, $user, $method)
	{
		// Clear rate limiting
		RateLimitService::clear_rate_limit($user_id);

		// Clear the authentication token
		TokenService::clear_auth_token($user_id);

		// Clean up 2FA session transients for this user
		self::cleanup_user_transients($user_id);

		// Track 2FA session for user management (Pro feature)
		if (class_exists('\WPUltimateSecurity\UltimateSecurityPro\Modules\Authentication\TwoFactor\Services\SessionService')) {
			$options = Utils::ultimate_security_get_option();
			$session_duration = (int) ($options['security']['2fa_authentication']['session_duration'] ?? 30);
			\WPUltimateSecurity\UltimateSecurityPro\Modules\Authentication\TwoFactor\Services\SessionService::track_session($user_id, $session_duration);
		}

		// Handle "Remember this device" checkbox (Pro feature)
		if (isset($_POST['remember_device']) && $_POST['remember_device'] === '1') {
			if (ProFeatureMiddleware::hasProFeature('trusted_devices') && TrustedDeviceService::is_enabled()) {
				$device_result = TrustedDeviceService::trust_device($user_id);

				// Log trusted device addition
				if ($device_result && class_exists('\WPUltimateSecurity\UltimateSecurityPro\Modules\Authentication\TwoFactor\Storage\LogRepository')) {
					$options = Utils::ultimate_security_get_option();
					if (!empty($options['security']['2fa_authentication']['audit_logs']['enable'])) {
						\WPUltimateSecurity\UltimateSecurityPro\Modules\Authentication\TwoFactor\Storage\LogRepository::log_event($user_id, '2fa_trusted_device_added', [
							'device_name' => $device_result['device_name'] ?? 'Unknown',
							'ip_address' => DeviceFingerprint::get_client_ip(),
							'timestamp' => DateHelper::now()
						]);
					}
				}
			}
		}

		// Fire action for SimpleEventLogger and other listeners
		do_action('ultimate_security_2fa_verified', $user_id, $method);

		// Log successful verification (Pro enhanced logging)
		$options = Utils::ultimate_security_get_option();
		if (!empty($options['security']['2fa_authentication']['audit_logs']['enable'])) {
			if (class_exists('\WPUltimateSecurity\UltimateSecurityPro\Modules\Authentication\TwoFactor\Storage\LogRepository')) {
				\WPUltimateSecurity\UltimateSecurityPro\Modules\Authentication\TwoFactor\Storage\LogRepository::log_event($user_id, '2fa_verification_success', [
					'method' => $method,
					'ip_address' => DeviceFingerprint::get_client_ip(),
					'timestamp' => DateHelper::now()
				]);
			}
		}

		// Clean up all 2FA metadata
		delete_user_meta($user_id, 'ultimate_security_2fa_code');
		delete_user_meta($user_id, 'ultimate_security_2fa_code_expires');
		delete_user_meta($user_id, 'ultimate_security_2fa_pending');
		delete_user_meta($user_id, '_ultimate_security_2fa_login_pending'); // Clean up persistent marker
		delete_transient('2fa_code_generation_' . $user_id);

		// Set authentication cookie and log in
		wp_set_auth_cookie($user_id, true);
		wp_set_current_user($user_id);
		do_action('wp_login', $user->user_login, $user);

		// Get redirect URL
		$redirect_to = get_user_meta($user_id, 'ultimate_security_2fa_redirect_to', true);
		if (empty($redirect_to)) {
			$redirect_to = admin_url();
		}

		// Handle WooCommerce login redirect
		$is_woocommerce_login = get_user_meta($user_id, 'ultimate_security_2fa_woocommerce_login', true);
		if ($is_woocommerce_login) {
			delete_user_meta($user_id, 'ultimate_security_2fa_woocommerce_login');

			if (function_exists('is_plugin_active') && is_plugin_active('woocommerce/woocommerce.php')) {
				if (function_exists('wc_get_page_permalink')) {
					$redirect_to = wc_get_page_permalink('myaccount');
				} else {
					$redirect_to = home_url('/my-account/');
				}
			} else {
				$redirect_to = home_url('/my-account/');
			}
		}

		// Clean up redirect meta
		delete_user_meta($user_id, 'ultimate_security_2fa_redirect_to');

		wp_safe_redirect($redirect_to);
		exit;
	}

	/**
	 * Send 2FA notification email
	 *
	 * @param int $user_id User ID
	 * @param string $event_type Event type
	 * @param array $data Additional data
	 * @return bool Success status
	 */
	protected static function send_notification($user_id, $event_type, $data = [])
	{
		$user = get_userdata($user_id);
		if (!$user) {
			return false;
		}

		$subject = '';
		$message = '';

		switch ($event_type) {
			case '2fa_enabled':
				$subject = __('Two-Factor Authentication Enabled', 'ultimate-security');
				$message = sprintf(
					/* translators: 1: User email, 2: Site name */
					__('Two-factor authentication has been enabled for your account (%1$s) on %2$s.', 'ultimate-security'),
					$user->user_email,
					get_bloginfo('name')
				);
				break;

			case '2fa_disabled':
				$subject = __('Two-Factor Authentication Disabled', 'ultimate-security');
				$message = sprintf(
					/* translators: 1: User email, 2: Site name */
					__('Two-factor authentication has been disabled for your account (%1$s) on %2$s.', 'ultimate-security'),
					$user->user_email,
					get_bloginfo('name')
				);
				break;

			case '2fa_lockout':
				$subject = __('Account Locked Due to Failed 2FA Attempts', 'ultimate-security');
				$message = sprintf(
					/* translators: 1: User email, 2: Site name */
					__('Your account (%1$s) on %2$s has been temporarily locked due to too many failed two-factor authentication attempts. If this wasn\'t you, please contact support immediately.', 'ultimate-security'),
					$user->user_email,
					get_bloginfo('name')
				);
				break;
		}

		if ($subject && $message) {
			$headers = ['Content-Type: text/html; charset=UTF-8'];
			return wp_mail($user->user_email, $subject, $message, $headers);
		}

		return false;
	}

	/**
	 * Clean up all transients for a specific user
	 *
	 * @param int $user_id User ID
	 */
	public static function cleanup_user_transients($user_id)
	{
		global $wpdb;
		
		$transient_prefix = '_transient_ultimate_security_2fa_session_';
		$transients = $wpdb->get_col($wpdb->prepare(
			"SELECT option_name FROM $wpdb->options WHERE option_name LIKE %s AND option_value IS NOT NULL",
			$transient_prefix . '%'
		));

		foreach ($transients as $transient_name) {
			$session_data = get_transient(str_replace('_transient_', '', $transient_name));
			
			if ($session_data && is_array($session_data) && isset($session_data['user_id'])) {
				if ($session_data['user_id'] == $user_id) {
					delete_transient(str_replace('_transient_', '', $transient_name));
				}
			}
		}
	}

	/**
	 * Clean up stale 2FA markers for expired tokens
	 *
	 * This method cleans up user meta markers for tokens that have expired
	 * to prevent orphaned markers from accumulating
	 */
	private static function cleanup_stale_2fa_markers()
	{
		global $wpdb;
		
		// Get all users with pending 2FA markers
		$pending_users = $wpdb->get_col($wpdb->prepare(
			"SELECT user_id FROM $wpdb->usermeta WHERE meta_key = %s",
			'_ultimate_security_2fa_login_pending'
		));

		foreach ($pending_users as $user_id) {
			$user_id = absint($user_id);
			
			// Check if the user has a valid auth token
			if (!TokenService::has_pending_token($user_id)) {
				// Token has expired or doesn't exist, clean up markers
				delete_user_meta($user_id, 'ultimate_security_2fa_pending');
				delete_user_meta($user_id, '_ultimate_security_2fa_login_pending');
				// Also clean up any related transients
				self::cleanup_user_transients($user_id);
			}
		}
	}

	/**
	 * Legacy handler for old URL-based verification page
	 * Redirects to the new wp-login.php based verification
	 *
	 * @deprecated Use handle_verification_page() with login_init hook instead
	 */
	public static function handle_legacy_verification_page()
	{
		$request_uri = isset($_SERVER['REQUEST_URI']) ? sanitize_text_field(wp_unslash($_SERVER['REQUEST_URI'])) : '';

		if (strpos($request_uri, '/ultimate-security-2fa-verification') !== false) {
			// Redirect to login page with error
			wp_safe_redirect(add_query_arg('login_error', 'session_expired', wp_login_url()));
			exit;
		}
	}
}
