<?php
declare(strict_types=1);

namespace WPUltimateSecurity\UltimateSecurity\Modules\Protection;

use WPUltimateSecurity\UltimateSecurity\Support\Helpers\Utils;
use WPUltimateSecurity\UltimateSecurity\Support\Helpers\IpHelper;
use WPUltimateSecurity\UltimateSecurity\Modules\TestMode\TestModeService;
use WPUltimateSecurity\UltimateSecurity\Modules\Base\AbstractModule;
use WP_Error;
use WP_REST_Response;

class CloudflareTurnstile extends AbstractModule
{
	/**
	 * Module identifier.
	 */
	public const MODULE_ID = 'protection.turnstile';

	/**
	 * Module version.
	 */
	protected const VERSION = '2.0.0';

	protected static $cfturnstile_options;
	protected static $log_option_name = 'ultimate_security_turnstile_log';
	protected static $max_log_entries = 100; // Maximum number of log entries to store

	/**
	 * Get the unique module identifier.
	 *
	 * @return string
	 */
	public static function getId(): string
	{
		return self::MODULE_ID;
	}

	/**
	 * Get the human-readable module name.
	 *
	 * @return string
	 */
	public static function getName(): string
	{
		return __('Cloudflare Turnstile', 'ultimate-security');
	}

	/**
	 * Get the module domain.
	 *
	 * @return string
	 */
	public static function getDomain(): string
	{
		return 'protection';
	}

	/**
	 * Boot the module (registers hooks and handlers).
	 *
	 * @return void
	 */
	public static function boot(): void
	{
		$GLOBALS['ultimate_security_turnstile_failed'] = false;
		$options = Utils::ultimate_security_get_option();
		self::$cfturnstile_options = isset($options['security']['cloudflare_turnstile']) ? $options['security']['cloudflare_turnstile'] : [
			'site_key' => '',
			'secret_key' => '',
			'theme' => '',
			'language' => '',
			'disable_submit_button' => 0,
			'widget_size' => '',
			'appearance_mode' => '',
			'defer_scripts' => 0,
			'custom_error_message' => '',
			'extra_failure_message' => 0,
			'failure_message' => '',
			'logged_in_users' => 0,
			'ip_addresses' => '',
			'user_agents' => '',

			'wordpress_login' => 0,
			'wordpress_register' => 0,
			'wordpress_reset_password' => 0,
			'wordpress_comment' => 0,

		];
		// Enqueue Turnstile script
		add_action('admin_enqueue_scripts', [self::class, 'ultimate_security_enqueue_turnstile_script']);
		add_action('wp_enqueue_scripts', [self::class, 'ultimate_security_enqueue_turnstile_script']);
		add_action('login_enqueue_scripts', [self::class, 'ultimate_security_enqueue_turnstile_script']);

		// Also enqueue on custom login pages (when wp-login.php is included via LoginControl)
		add_action('login_init', [self::class, 'ultimate_security_enqueue_turnstile_script']);

		// Original hook
		add_action('sclm_captha', [self::class, 'sclm_captha_element']);
		// WordPress login form - check for reCAPTCHA conflict
		$recaptcha_enabled_for_login = isset($options['security']['re_captcha']['enable']) && $options['security']['re_captcha']['enable'];
		if (isset(self::$cfturnstile_options['wordpress_login']) && self::$cfturnstile_options['wordpress_login']) {
			// if ($recaptcha_enabled_for_login) {
			// 	// Log conflict but don't add both CAPTCHAs - Turnstile takes precedence
			// 	error_log('Ultimate Security: Both Turnstile and reCAPTCHA are enabled for login. Using Turnstile only.');
			// }
			add_action('login_form', [self::class, 'add_turnstile_to_login_form'], 999999);
			add_action('woocommerce_login_form', [self::class, 'add_turnstile_to_login_form'], 999999);
		}
		// WordPress registration form
		if (isset(self::$cfturnstile_options['wordpress_register']) && self::$cfturnstile_options['wordpress_register']) {
			add_action('register_form', [self::class, 'add_turnstile_to_register_form']);
			add_action('woocommerce_register_form', [self::class, 'add_turnstile_to_register_form'], 999999);
		}

		// WordPress reset password form
		if (isset(self::$cfturnstile_options['wordpress_reset_password']) && self::$cfturnstile_options['wordpress_reset_password']) {
			add_action('lostpassword_form', [self::class, 'add_turnstile_to_lostpassword_form']);
		}

		// WordPress comments form
		if (isset(self::$cfturnstile_options['wordpress_comment']) && self::$cfturnstile_options['wordpress_comment']) {
			// add_action('comment_form_after_fields', [self::class, 'add_turnstile_to_comment_form']);
			// add_action('comment_form_logged_in_after', [self::class, 'add_turnstile_to_comment_form']);
			add_action('comment_form', [self::class, 'add_turnstile_to_comment_form'], 10);
		}

		// Validation actions - Only add these if the respective form has Turnstile enabled
		add_filter('authenticate', [self::class, 'verify_login_turnstile'], 99, 3);
		add_filter('registration_errors', [self::class, 'verify_register_turnstile'], 10, 3);
		add_action('lostpassword_post', [self::class, 'verify_lostpassword_turnstile']);
		add_filter('preprocess_comment', [self::class, 'verify_comment_turnstile']);

		// Register REST API route for logs
		add_action('rest_api_init', [self::class, 'register_turnstile_log_endpoint']);
	}

	// Register REST API endpoint for turnstile logs
	public static function register_turnstile_log_endpoint()
	{
		register_rest_route('ultimate-security/v1', '/turnstile-logs', [
			'methods' => 'GET',
			'callback' => [self::class, 'get_turnstile_logs'],
			'permission_callback' => function () {
				return current_user_can('manage_options');
			}
		]);
	}

	// REST API callback to get turnstile logs
	public static function get_turnstile_logs($request)
	{
		$logs = get_option(self::$log_option_name, []);

		// Optional pagination parameters
		$page = isset($request['page']) ? (int) $request['page'] : 1;
		$per_page = isset($request['per_page']) ? (int) $request['per_page'] : 20;

		// Calculate pagination
		$total_items = count($logs);
		$max_pages = ceil($total_items / $per_page);
		$offset = ($page - 1) * $per_page;

		// Slice the array for pagination
		$logs = array_slice($logs, $offset, $per_page);

		$response = new WP_REST_Response($logs);
		$response->header('X-WP-Total', $total_items);
		$response->header('X-WP-TotalPages', $max_pages);

		return $response;
	}

	public static function ultimate_security_enqueue_turnstile_script()
	{
		$ultimate_security_defer_scripts = isset(self::$cfturnstile_options['defer_scripts']) ? esc_html(self::$cfturnstile_options['defer_scripts']) : '0';

		$defer = $ultimate_security_defer_scripts ? 'defer' : '';
		wp_enqueue_script('cf-turnstile', 'https://challenges.cloudflare.com/turnstile/v0/api.js', [], null, true);
		if ($defer) {
			add_filter('script_loader_tag', [self::class, 'ultimate_security_add_defer_attribute'], 10, 3);
		}
		/* Disable Submit Button */
		if (isset(self::$cfturnstile_options['disable_submit_button']) && self::$cfturnstile_options['disable_submit_button']) {
			wp_register_script('ultimate-security-disable-submit', ULTIMATE_SECURITY_URL . 'assets/admin/js/disable-submit.js', array(), '1.0', true);
			wp_enqueue_script('ultimate-security-disable-submit');
		}


	}

	public static function ultimate_security_add_defer_attribute($tag, $handle, $src)
	{
		if ('cf-turnstile' === $handle) {
			return '<script src="' . esc_url($src) . '" defer></script>';
		}
		return $tag;
	}

	public static function sclm_captha_element()
	{
		if (self::ultimate_security_is_whitelisted()) {
			return '';
		}
		$turnstile_html = self::ultimate_security_render_turnstile();
		echo wp_kses_post($turnstile_html);
	}

	/**
	 * Get IP Address - checks multiple server variables
	 * 
	 * @return string|false The IP address or false if not found
	 */
	public static function ultimate_security_get_ip()
	{
		if (isset($_SERVER)) {
			$vars = array('REMOTE_ADDR', 'HTTP_X_REAL_IP', 'HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR');
			foreach ($vars as $var) {
				if (isset($_SERVER[$var])) {
					$ips = explode(',', sanitize_text_field(wp_unslash($_SERVER[$var])));
					// Handle comma-separated values
					foreach ($ips as $ip) {
						$ip = trim($ip);
						if (filter_var($ip, FILTER_VALIDATE_IP)) {
							return $ip;
						}
					}
				}
			}
		}
		return false; // Return false if no valid IP found
	}

	/**
	 * Check if the current request is whitelisted
	 * 
	 * @return boolean True if whitelisted, false otherwise
	 */
	public static function ultimate_security_is_whitelisted()
	{
		$ultimate_security_whitelist_logged_in = isset(self::$cfturnstile_options['logged_in_users']) ?
			(bool) self::$cfturnstile_options['logged_in_users'] : false;

		// Check if logged-in users are whitelisted
		if ($ultimate_security_whitelist_logged_in && is_user_logged_in()) {
			return true;
		}

		// Apply filters to allow third-party integrations
		$whitelisted = apply_filters('ultimate_security_turnstile_whitelisted', false);
		if ($whitelisted) {
			return true;
		}

		// Check if IP address is whitelisted
		$ip_addresses = isset(self::$cfturnstile_options['ip_addresses']) ?
			self::$cfturnstile_options['ip_addresses'] : [];

		if (!empty($ip_addresses) && is_array($ip_addresses)) {
			$current_ip = self::ultimate_security_get_ip();

			foreach ($ip_addresses as $ip_entry) {
				if (isset($ip_entry['value'])) {
					$whitelist_ip = sanitize_text_field(trim($ip_entry['value']));
					// Skip invalid inputs
					if (!filter_var($whitelist_ip, FILTER_VALIDATE_IP)) {
						continue;
					}
					// Check if the IP is exactly equal
					if ($current_ip && $current_ip == $whitelist_ip) {
						return true;
					}
				}
			}
		}

		// Check if User Agent is whitelisted
		$user_agents = isset(self::$cfturnstile_options['user_agents']) ?
			self::$cfturnstile_options['user_agents'] : [];

		if (!empty($user_agents) && is_array($user_agents)) {
			$current_agent = isset($_SERVER['HTTP_USER_AGENT']) ? sanitize_text_field($_SERVER['HTTP_USER_AGENT']) : '';

			if (!empty($current_agent)) {
				foreach ($user_agents as $agent_entry) {
					if (isset($agent_entry['value'])) {
						$whitelist_agent = sanitize_text_field(trim($agent_entry['value']));
						// Check if the User Agent contains the whitelist agent
						if (!empty($whitelist_agent) && strpos($current_agent, $whitelist_agent) !== false) {
							return true;
						}
					}
				}
			}
		}

		return false;
	}

	/**
	 * Check if Turnstile is enabled for a specific form type
	 * 
	 * @param string $form_type The form type to check
	 * @return boolean True if enabled, false otherwise
	 */
	public static function is_turnstile_enabled_for_form($form_type)
	{
		switch ($form_type) {
			case 'login':
				return isset(self::$cfturnstile_options['wordpress_login']) &&
					self::$cfturnstile_options['wordpress_login'];
			case 'register':
				return isset(self::$cfturnstile_options['wordpress_register']) &&
					self::$cfturnstile_options['wordpress_register'];
			case 'lostpassword':
				return isset(self::$cfturnstile_options['wordpress_reset_password']) &&
					self::$cfturnstile_options['wordpress_reset_password'];
			case 'comment':
				return isset(self::$cfturnstile_options['wordpress_comment']) &&
					self::$cfturnstile_options['wordpress_comment'];
			default:
				return true; // Default to enabled for safety
		}
	}

	public static function ultimate_security_render_turnstile($custom_class = '')
	{
		$site_key = isset(self::$cfturnstile_options['site_key']) ? esc_html(self::$cfturnstile_options['site_key']) : '';
		$theme = isset(self::$cfturnstile_options['theme']) ? esc_html(self::$cfturnstile_options['theme']) : 'auto';
		$size = isset(self::$cfturnstile_options['widget_size']) ? esc_html(self::$cfturnstile_options['widget_size']) : 'normal';
		$language = isset(self::$cfturnstile_options['language']) ? esc_html(self::$cfturnstile_options['language']) : 'auto';
		$appearance = isset(self::$cfturnstile_options['appearance_mode']) ? esc_html(self::$cfturnstile_options['appearance_mode']) : 'always';

		// Extra failure message functionality
		$extra_failure_message_enabled = isset(self::$cfturnstile_options['extra_failure_message']) ? (bool) self::$cfturnstile_options['extra_failure_message'] : false;
		$extra_failure_message = isset(self::$cfturnstile_options['failure_message']) ? wp_kses_post(self::$cfturnstile_options['failure_message']) : '';

		$attributes = [
			'data-sitekey' => $site_key,
			'data-theme' => $theme,
			'data-size' => $size,
			'data-language' => $language,
			'data-appearance' => $appearance,
		];

		if (isset(self::$cfturnstile_options['disable_submit_button']) && self::$cfturnstile_options['disable_submit_button']) {
			$attributes['data-callback'] = 'ultimate_securityTurnstileCallback';
		}

		$attr_html = '';
		foreach ($attributes as $key => $value) {
			$attr_html .= sprintf(' %s="%s"', $key, esc_attr($value));
		}

		$class = 'cf-turnstile';
		if (!empty($custom_class)) {
			$class .= ' ' . esc_attr($custom_class);
		}

		$output = sprintf('<div class="%s"%s></div>', $class, $attr_html);

		// Add error message div and JavaScript if extra failure message is enabled
		if ($extra_failure_message_enabled && !empty($extra_failure_message) && !empty($GLOBALS['ultimate_security_turnstile_failed'])) {
			$output .= '<div id="turnstile-error-message" style="margin-top:10px; color:#f00; font-weight:bold;">' . $extra_failure_message . '</div>';
		}

		return $output;
	}

	// Add Turnstile to login form
	public static function add_turnstile_to_login_form()
	{
		if (self::ultimate_security_is_whitelisted()) {
			return;
		}
		?>
		<div style="margin-bottom: 20px;margin-left: -15px;">
			<?php echo wp_kses_post(self::ultimate_security_render_turnstile('turnstile-login')); ?>

		</div>
		<?php
	}

	// Add Turnstile to registration form
	public static function add_turnstile_to_register_form()
	{
		if (self::ultimate_security_is_whitelisted()) {
			return;
		}
		?>
		<div style="margin-bottom: 20px;margin-left: -15px;">
			<?php echo wp_kses_post(self::ultimate_security_render_turnstile('turnstile-register')); ?>
		</div>
		<?php
	}

	// Add Turnstile to lost password form
	public static function add_turnstile_to_lostpassword_form()
	{
		if (self::ultimate_security_is_whitelisted()) {
			return;
		}
		?>
		<div style="margin-bottom: 20px;margin-left: -15px;">
			<?php echo wp_kses_post(self::ultimate_security_render_turnstile('turnstile-lostpassword')); ?>
		</div>
		<?php
	}

	// Add Turnstile to comment form
	public static function add_turnstile_to_comment_form()
	{
		if (self::ultimate_security_is_whitelisted()) {
			return;
		}
		?>
		<div style="margin-bottom: 20px;margin-left: -15px;">
			<?php echo wp_kses_post(self::ultimate_security_render_turnstile('turnstile-comment')); ?>
		</div>
		<?php
	}

	/**
	 * Add a new entry to the Turnstile log
	 * 
	 * @param boolean $success Whether the verification was successful
	 * @param string $response The response message
	 * @param array $extra_info Additional information to log
	 */
	private static function add_log_entry($success, $response, $extra_info = [])
	{
		$logs = get_option(self::$log_option_name, []);

		// Prepare the log entry
		$log_entry = [
			'date' => current_time('mysql'),
			'timestamp' => time(),
			'success' => $success,
			'response' => $response,
			'info' => [
				'ip' => self::ultimate_security_get_ip(),
				'url' => isset($_SERVER['REQUEST_URI']) ? sanitize_text_field($_SERVER['REQUEST_URI']) : '',
				'user_agent' => isset($_SERVER['HTTP_USER_AGENT']) ? sanitize_text_field($_SERVER['HTTP_USER_AGENT']) : '',
			]
		];

		// Add any extra info
		if (!empty($extra_info)) {
			$log_entry['info'] = array_merge($log_entry['info'], $extra_info);
		}

		// Add new log at the beginning of the array (latest first)
		array_unshift($logs, $log_entry);

		// Limit the number of logs
		if (count($logs) > self::$max_log_entries) {
			$logs = array_slice($logs, 0, self::$max_log_entries);
		}

		// Update the option
		update_option(self::$log_option_name, $logs);
	}

	// Verify Turnstile response for login
	public static function verify_login_turnstile($user, $username, $password)
	{
		// Skip verification if Turnstile is disabled for login form
		if (!self::is_turnstile_enabled_for_form('login')) {
			return $user;
		}

		// Skip verification if whitelisted
		if (self::ultimate_security_is_whitelisted() || empty($username) || empty($password)) {
			return $user;
		}

		$verification = self::verify_turnstile_response('login');

		if (is_wp_error($verification)) {
			return new WP_Error('turnstile_error', $verification->get_error_message());
		}

		return $user;
	}

	// Verify Turnstile response for registration
	public static function verify_register_turnstile($errors, $sanitized_user_login, $user_email)
	{
		// Skip verification if Turnstile is disabled for registration form
		if (!self::is_turnstile_enabled_for_form('register')) {
			return $errors;
		}

		// Skip verification if whitelisted
		if (self::ultimate_security_is_whitelisted()) {
			return $errors;
		}

		$verification = self::verify_turnstile_response('register');

		if (is_wp_error($verification)) {
			$errors->add('turnstile_error', $verification->get_error_message());
		}

		return $errors;
	}

	// Verify Turnstile response for lost password
	public static function verify_lostpassword_turnstile($errors)
	{
		// Skip verification if Turnstile is disabled for lost password form
		if (!self::is_turnstile_enabled_for_form('lostpassword')) {
			return;
		}

		// Skip verification if whitelisted
		if (self::ultimate_security_is_whitelisted()) {
			return;
		}

		$verification = self::verify_turnstile_response('lostpassword');

		if (is_wp_error($verification)) {
			wp_die(esc_html($verification->get_error_message()), 'Error', ['response' => 403, 'back_link' => true]);
		}
	}

	// Verify Turnstile response for comments
	public static function verify_comment_turnstile($commentdata)
	{
		// Skip verification if Turnstile is disabled for comment form
		if (!self::is_turnstile_enabled_for_form('comment')) {
			return $commentdata;
		}

		// Skip verification if whitelisted or user is logged in
		if (self::ultimate_security_is_whitelisted() || is_user_logged_in()) {
			return $commentdata;
		}

		$verification = self::verify_turnstile_response('comment');

		if (is_wp_error($verification)) {
			wp_die(esc_html($verification->get_error_message()), 'Error', ['response' => 403, 'back_link' => true]);
		}

		return $commentdata;
	}

	// Common function to verify Turnstile response
	private static function verify_turnstile_response($form_type = 'generic')
	{
		// Test Mode: Log simulation and skip verification
		if (TestModeService::shouldSimulate()) {
			$hasTurnstileResponse = isset($_POST['cf-turnstile-response']);
			TestModeService::logSimulation(
				'cloudflare_turnstile',
				'verification_bypassed',
				__('Turnstile verification would be required', 'ultimate-security'),
				[
					'form_type' => $form_type,
					'has_response' => $hasTurnstileResponse,
				]
			);
			return true; // Allow to proceed
		}

		$secret_key = isset(self::$cfturnstile_options['secret_key']) ? esc_html(self::$cfturnstile_options['secret_key']) : '';

		// Get custom error message if set
		$custom_error_message = isset(self::$cfturnstile_options['custom_error_message']) && !empty(self::$cfturnstile_options['custom_error_message'])
			? esc_html(self::$cfturnstile_options['custom_error_message'])
			: __('Please complete the Cloudflare Turnstile challenge.', 'ultimate-security');

		// Check if the turnstile response exists
		if (!isset($_POST['cf-turnstile-response'])) {
			self::add_log_entry(false, 'Required', ['form_type' => $form_type, 'error' => __('Turnstile response missing','ultimate-security')]);
			return new WP_Error('turnstile_required', $custom_error_message);
		}

		$turnstile_response = sanitize_text_field($_POST['cf-turnstile-response']);

		// Make the verification request to Cloudflare
		$response = wp_remote_post('https://challenges.cloudflare.com/turnstile/v0/siteverify', [
			'body' => [
				'secret' => $secret_key,
				'response' => $turnstile_response,
				'remoteip' => IpHelper::getClientIp(),
			]
		]);

		// Check for connection errors
		if (is_wp_error($response)) {
			$error_message = $response->get_error_message();
			self::add_log_entry(false, 'Connection Error', [
				'form_type' => $form_type,
				'error' => $error_message
			]);
			return new WP_Error('turnstile_connection_error', __('Failed to verify Turnstile challenge. Please try again.', 'ultimate-security'));
		}

		$body = wp_remote_retrieve_body($response);
		$data = json_decode($body, true);

		// Check if verification was successful
		if (!isset($data['success']) || $data['success'] !== true) {
			$error_codes = isset($data['error-codes']) ? implode(', ', $data['error-codes']) : 'unknown';
			self::add_log_entry(false, 'Verification Failed', [
				'form_type' => $form_type,
				'error_codes' => $error_codes
			]);

			// Set global flag to show extra failure message
			$GLOBALS['ultimate_security_turnstile_failed'] = true;

			return new WP_Error('turnstile_verification_failed', $custom_error_message);
		}

		// Log successful verification
		self::add_log_entry(true, 'Success', [
			'form_type' => $form_type,
			'hostname' => $data['hostname'] ?? '',
			'challenge_ts' => $data['challenge_ts'] ?? '',
			'action' => $data['action'] ?? ''
		]);

		return true;
	}
}
