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

use WPUltimateSecurity\UltimateSecurity\Contracts\TwoFactorProviderInterface;
use WPUltimateSecurity\UltimateSecurity\Support\Helpers\Utils;
use WPUltimateSecurity\UltimateSecurity\Support\Helpers\DateHelper;

/**
 * Email 2FA Provider
 *
 * Handles email-based two-factor authentication.
 * Implements TwoFactorProviderInterface for consistent 2FA provider API.
 *
 * @implements TwoFactorProviderInterface
 */
class EmailProvider implements TwoFactorProviderInterface
{
	/**
	 * Provider name for display
	 */
	private const PROVIDER_NAME = 'Email Authentication';

	/**
	 * Provider slug for internal use
	 */
	private const PROVIDER_SLUG = 'email';

	/**
	 * Settings key in plugin options
	 */
	private const SETTINGS_KEY = '2fa_email';

	// =========================================================================
	// TwoFactorProviderInterface Implementation
	// =========================================================================

	/**
	 * {@inheritdoc}
	 */
	public function isEnabledForUser(int $userId): bool
	{
		return self::is_enabled_for_user($userId);
	}

	/**
	 * {@inheritdoc}
	 */
	public function enableForUser(int $userId): bool
	{
		return self::enable_for_user($userId);
	}

	/**
	 * {@inheritdoc}
	 */
	public function disableForUser(int $userId): bool
	{
		return self::disable_for_user($userId);
	}

	/**
	 * {@inheritdoc}
	 */
	public function sendCode(int $userId): bool
	{
		$result = self::send_verification_code($userId);
		return $result !== false;
	}

	/**
	 * {@inheritdoc}
	 */
	public function verifyCode(int $userId, string $code): bool
	{
		return self::verify_code($userId, $code);
	}

	/**
	 * {@inheritdoc}
	 */
	public function getProviderName(): string
	{
		return __('Email Authentication', 'ultimate-security');
	}

	/**
	 * {@inheritdoc}
	 */
	public function getProviderSlug(): string
	{
		return self::PROVIDER_SLUG;
	}

	/**
	 * {@inheritdoc}
	 */
	public function getSettingsKey(): string
	{
		return self::SETTINGS_KEY;
	}

	// =========================================================================
	// Static Methods (Backward Compatibility)
	// =========================================================================

	/**
	 * Send verification code via email
	 *
	 * @param int $user_id User ID
	 * @return string|false Verification code or false on failure
	 */
	public static function send_verification_code($user_id)
	{
		$user = get_userdata($user_id);
		if (!$user) {
			return false;
		}
		$lock_key = "2fa_code_generation_{$user_id}";
		$resend_cooldown_key = "2fa_resend_cooldown_{$user_id}";
		$existing_code = get_user_meta($user_id, 'ultimate_security_2fa_code', true);
		$code_expires = get_user_meta($user_id, 'ultimate_security_2fa_code_expires', true);

		// Clean up expired codes so we can generate a fresh one
		if ($code_expires && time() > $code_expires) {
			delete_user_meta($user_id, 'ultimate_security_2fa_code');
			delete_user_meta($user_id, 'ultimate_security_2fa_code_expires');
			delete_transient($lock_key);
			$existing_code = null;
			$code_expires = null;
		}

		$is_resend = get_transient($lock_key) ? true : false;

		// Set a short-lived lock to avoid parallel code generation
		set_transient($lock_key, ['in_progress' => true], 60);

		$verification_code = wp_rand(100000, 999999);
		$hashed_code = wp_hash_password($verification_code);
		update_user_meta($user_id, 'ultimate_security_2fa_code', $hashed_code);

		// Set expiration time for the code (5 minutes)
		update_user_meta($user_id, 'ultimate_security_2fa_code_expires', time() + 300);

		return self::send_code_email($user, $verification_code, $lock_key, $is_resend) ? $verification_code : false;
	}


	public static function verify_code($user_id, $entered_code)
	{
		$stored_code = get_user_meta($user_id, 'ultimate_security_2fa_code', true);
		if (!$stored_code) {
			return false;
		}

		// Check if code has expired
		$code_expires = get_user_meta($user_id, 'ultimate_security_2fa_code_expires', true);
		if ($code_expires && time() > $code_expires) {
			// Clean up expired code
			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 false;
		}

		// Use timing-safe comparison with password verification
		return wp_check_password($entered_code, $stored_code);
	}

	/**
	 * Check if email 2FA is enabled for user
	 *
	 * Admin-enforced 2FA: If user's role is in the allowed roles list, 2FA is required
	 * User-enabled 2FA: If user has manually enabled 2FA for themselves
	 *
	 * @param int $user_id User ID
	 * @return bool True if enabled
	 */
	public static function is_enabled_for_user($user_id)
	{
		$user = get_userdata($user_id);
		if (!$user) {
			return false;
		}

		$options = Utils::ultimate_security_get_option();
		$enable_email_verification = isset($options['security']['2fa_authentication']['email_authentication']['2fa_email_verification_enable'])
			? sanitize_text_field(wp_unslash($options['security']['2fa_authentication']['email_authentication']['2fa_email_verification_enable']))
			: 0;

		if (!$enable_email_verification) {
			return false;
		}

		$email_verification_enable_for = isset($options['security']['2fa_authentication']['email_authentication']['2fa_email_verification_enable_for'])
			? wp_unslash($options['security']['2fa_authentication']['email_authentication']['2fa_email_verification_enable_for'])
			: [];

		$allowed_user_roles = [];
		if ($email_verification_enable_for) {
			foreach ($email_verification_enable_for as $role) {
				$allowed_user_roles[] = $role;
			}
		}

		$email_allowed_user_roles = array_intersect($allowed_user_roles, $user->roles);

		// Admin-enforced 2FA: User's role is in the allowed roles list
		// This takes precedence - if admin enforces 2FA for a role, user must comply
		if (!empty($email_allowed_user_roles)) {
			return true;
		}

		// User-enabled 2FA: User manually enabled 2FA for themselves (optional)
		$ultimate_security_enable_email_authentication = get_user_meta($user->ID, 'ultimate_security_enable_email_authentication', true);

		return (bool) $ultimate_security_enable_email_authentication;
	}

	/**
	 * Enable email authentication for user
	 *
	 * @param int $user_id User ID
	 * @return bool Success status
	 */
	public static function enable_for_user($user_id)
	{
		update_user_meta($user_id, 'ultimate_security_enable_email_authentication', 1);
		return true;
	}

	/**
	 * Disable email authentication for user
	 *
	 * @param int $user_id User ID
	 * @return bool Success status
	 */
	public static function disable_for_user($user_id)
	{
		delete_user_meta($user_id, 'ultimate_security_enable_email_authentication');
		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);
		delete_transient('2fa_resend_cooldown_' . $user_id);
		return true;
	}

	/**
	 * Send the verification email and handle logging/locks
	 *
	 * @param \WP_User $user User object
	 * @param string   $verification_code Code to send
	 * @param string   $lock_key Lock key for transients
	 * @param bool     $is_resend Whether this is a resend of an existing code
	 * @return bool
	 */
	private static function send_code_email($user, $verification_code, $lock_key, $is_resend = false)
	{
		$site_name = get_bloginfo('name');
		$message = sprintf(
			__("Hello %s,\n\nYour verification code for %s is: %s\n\nThis code will expire in 5 minutes.\n\nIf you didn't request this code, please ignore this email.\n\nThank you!", 'ultimate-security'),
			$user->display_name,
			$site_name,
			$verification_code
		);

		$sent = wp_mail(
			$user->user_email,
			sprintf(__('[%s] Your 2FA Verification Code', 'ultimate-security'), $site_name),
			$message
		);

		if (!$sent) {
			$error_message = 'Email 2FA code failed to send';

			global $phpmailer;
			if (isset($phpmailer) && is_object($phpmailer) && !empty($phpmailer->ErrorInfo)) {
				$error_message .= ': ' . $phpmailer->ErrorInfo;
			}

			error_log(sprintf(
				'[Ultimate Security] %s for user ID %d (email: %s)',
				$error_message,
				$user->ID,
				$user->user_email
			));
			if (Utils::ultimate_security_get_option()['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_email_send_failed', [
						'error' => $error_message,
						'recipient' => $user->user_email,
						'timestamp' => DateHelper::now(),
						'resent' => $is_resend,
					]);
				}
			}

			delete_transient($lock_key);
			delete_user_meta($user->ID, 'ultimate_security_2fa_code');
			delete_user_meta($user->ID, 'ultimate_security_2fa_code_expires');
			return false;
		}

		set_transient($lock_key, [
			'sent_at' => time(),
			'resent' => $is_resend,
		], 60);
		if (Utils::ultimate_security_get_option()['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, $is_resend ? '2fa_email_resent' : '2fa_email_sent', [
					'recipient' => $user->user_email,
					'timestamp' => DateHelper::now(),
					'resent' => $is_resend,
				]);
			}
		}
		return true;
	}
}
