<?php
/**
 * Username Changer Module
 *
 * Allows users to change their username directly from their profile page.
 * Implements security checks, validation, and proper database updates.
 *
 * @package UsernameChanger
 * @since 1.0.0
 */

namespace UsernameChanger;

use WP_PowerSuite\Core\AbstractModule;
use WP_PowerSuite\Core\RequestSanitizer;

/**
 * Username Changer Module Class
 *
 * @since 1.0.0
 */
class Module extends AbstractModule {

	private const MODULE_ID = 'username-changer';
	private const MODULE_VERSION = '1.2.0';

	/** @var bool */
	private static bool $woo_hooks_registered = false;

	/**
	 * Get Module ID
	 *
	 * @since 1.0.0
	 * @return string Module ID.
	 */
	public function getId(): string {
		return self::MODULE_ID;
	}

	/**
	 * Get Module Name
	 *
	 * @since 1.0.0
	 * @return string Module name.
	 */
	public function getName(): string {
		return __( 'Username Changer', 'wppowersuite-lite' );
	}

	/**
	 * Get Module Version
	 *
	 * @since 1.0.0
	 * @return string Module version.
	 */
	public function getVersion(): string {
		return self::MODULE_VERSION;
	}

	/**
	 * Get Module Description
	 *
	 * @since 1.0.0
	 * @return string Module description.
	 */
	public function getDescription(): string {
		return __( 'Let members update their login name from their profile when life changes—fix a typo, drop an old email-style handle, or match a new brand—without starting a second account. Built-in checks help keep names valid and unique.', 'wppowersuite-lite' );
	}

	/**
	 * Get Module Context
	 *
	 * @since 1.0.0
	 * @return string|array Module context.
	 */
	public function getContext(): string|array {
		return [ 'admin', 'frontend' ];
	}

	/**
	 * Get Module Dependencies
	 *
	 * @since 1.0.0
	 * @return array<string> Module dependencies.
	 */
	public function getDependencies(): array {
		return [];
	}

	private function isLicenseActive(): bool {
		return function_exists( 'wp_powersuite_is_license_valid' ) && wp_powersuite_is_license_valid();
	}

	/**
	 * Register hooks only when enabled (via AbstractModule::init).
	 */
	protected function registerHooks(): void {
		if ( ! $this->isLicenseActive() ) {
			return;
		}

		if ( is_admin() ) {
			add_action( 'show_user_profile', [ $this, 'addUsernameChangeField' ], 0 );
			add_action( 'edit_user_profile', [ $this, 'addUsernameChangeField' ], 0 );
			add_action( 'admin_head-profile.php', [ $this, 'hideDefaultUsernameField' ] );
			add_action( 'admin_head-user-edit.php', [ $this, 'hideDefaultUsernameField' ] );
			add_action( 'personal_options_update', [ $this, 'handleUsernameChange' ], 1 );
			add_action( 'edit_user_profile_update', [ $this, 'handleUsernameChange' ], 1 );
			add_action( 'admin_notices', [ $this, 'displayAdminNotices' ] );
			add_action( 'admin_enqueue_scripts', [ $this, 'enqueueAssets' ] );
			return;
		}

		if ( class_exists( 'WooCommerce', false ) ) {
			add_action( 'template_redirect', [ $this, 'maybeRegisterWooCommerceHooks' ], 5 );
		}
	}

	/**
	 * Registers WooCommerce hooks only on My Account / account-details POST (avoids global wp_head/wp_footer).
	 *
	 * @return void
	 */
	public function maybeRegisterWooCommerceHooks(): void {
		if ( self::$woo_hooks_registered ) {
			return;
		}
		if ( is_admin() || wp_doing_ajax() || wp_doing_cron() || ( defined( 'REST_REQUEST' ) && REST_REQUEST ) ) {
			return;
		}
		if ( ! $this->isWooAccountContext() ) {
			return;
		}

		self::$woo_hooks_registered = true;

		add_action( 'woocommerce_edit_account_form', [ $this, 'addWooCommerceUsernameField' ], 5 );
		add_action( 'woocommerce_save_account_details', [ $this, 'handleWooCommerceUsernameChange' ], 5 );
		add_action( 'wp_head', [ $this, 'addFrontendStyles' ], 20 );
		add_action( 'wp_footer', [ $this, 'addFrontendScripts' ], 20 );
	}

	/**
	 * True on My Account pages or when saving account details via POST.
	 */
	private function isWooAccountContext(): bool {
		if ( ! class_exists( 'WooCommerce' ) ) {
			return false;
		}
		if ( function_exists( 'is_account_page' ) && is_account_page() ) {
			return true;
		}
		// Form POST to edit-account (field presence only; handlers still verify nonces).
		if ( isset( $_POST['save_account_details'], $_POST['woocommerce-edit-account-nonce'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
			return true;
		}

		return false;
	}

	/**
	 * Add Username Change Field
	 *
	 * Adds a field to the user profile page allowing username changes.
	 *
	 * @since 1.0.0
	 * @param \WP_User $user Current user object.
	 * @return void
	 */
	public function addUsernameChangeField( \WP_User $user ): void {
		if ( ! current_user_can( 'edit_user', $user->ID ) ) {
			return;
		}

		// Don't show for super admins on multisite (unless current user is super admin)
		if ( is_multisite() && is_super_admin( $user->ID ) && ! is_super_admin() ) {
			return;
		}

		$current_username = $user->user_login;
		$can_change = $this->canUserChangeUsername( $user->ID );
		?>
		<div class="wp-powersuite-username-changer-section" style="margin-top: 20px;">
		<h2><?php esc_html_e( 'Username', 'wppowersuite-lite' ); ?></h2>
		<table class="form-table" role="presentation">
			<tbody>
				<tr>
					<th scope="row">
						<label for="current_username"><?php esc_html_e( 'Current Username', 'wppowersuite-lite' ); ?></label>
					</th>
					<td>
						<input 
							type="text" 
							id="current_username" 
							value="<?php echo esc_attr( $current_username ); ?>" 
							class="regular-text" 
							readonly 
							disabled
						/>
						<p class="description">
							<?php esc_html_e( 'Your current username. This field cannot be edited directly.', 'wppowersuite-lite' ); ?>
						</p>
					</td>
				</tr>
				<tr>
					<th scope="row">
						<label for="new_username"><?php esc_html_e( 'New Username', 'wppowersuite-lite' ); ?></label>
					</th>
					<td>
						<?php if ( $can_change ) : ?>
							<input 
								type="text" 
								name="new_username" 
								id="new_username" 
								value="" 
								class="regular-text" 
								autocomplete="off"
								placeholder="<?php esc_attr_e( 'Enter new username', 'wppowersuite-lite' ); ?>"
							/>
							<p class="description">
								<?php esc_html_e( 'Enter a new username. Leave blank to keep your current username. Username must be unique and contain only lowercase letters, numbers, underscores, hyphens, and periods.', 'wppowersuite-lite' ); ?>
							</p>
							<p class="description">
								<strong><?php esc_html_e( 'Important:', 'wppowersuite-lite' ); ?></strong>
								<?php esc_html_e( 'Changing your username updates your login name. You must sign in with the new username, active sessions will be signed out, and any pending password-reset links will stop working.', 'wppowersuite-lite' ); ?>
							</p>
							<div id="username-change-feedback" class="wp-powersuite-username-feedback" aria-live="polite" style="margin-top: 10px;"></div>
						<?php else : ?>
							<p class="description">
								<strong><?php esc_html_e( 'Username cannot be changed.', 'wppowersuite-lite' ); ?></strong>
								<?php if ( is_multisite() && is_super_admin( $user->ID ) ) : ?>
									<?php esc_html_e( 'Super admin usernames cannot be changed for security reasons.', 'wppowersuite-lite' ); ?>
								<?php endif; ?>
							</p>
						<?php endif; ?>
					</td>
				</tr>
			</tbody>
		</table>
		</div>
		<?php
		wp_nonce_field( 'wp_powersuite_change_username_' . $user->ID, 'wp_powersuite_username_nonce' );
	}

	/**
	 * Handle Username Change
	 *
	 * Processes username change request with security checks and validation.
	 *
	 * @since 1.0.0
	 * @param int $user_id User ID.
	 * @return void
	 */
	public function handleUsernameChange( int $user_id ): void {
		$this->processUsernameChangeRequest(
			$user_id,
			'wp_powersuite_username_nonce',
			'wp_powersuite_change_username_',
			'new_username',
			fn( string $message ) => $this->setNotice( 'error', $message ),
			fn( string $message ) => $this->setNotice( 'success', $message )
		);
	}

	/**
	 * Validate New Username
	 *
	 * Validates that the new username meets all requirements.
	 *
	 * @since 1.0.0
	 * @param string $new_username New username to validate.
	 * @param int    $user_id User ID.
	 * @return true|\WP_Error True if valid, WP_Error on failure.
	 */
	private function validateNewUsername( string $new_username, int $user_id ): bool|\WP_Error {
		if ( empty( $new_username ) ) {
			return new \WP_Error(
				'empty_username',
				__( 'Username cannot be empty.', 'wppowersuite-lite' )
			);
		}

		if ( strlen( $new_username ) < 3 ) {
			return new \WP_Error(
				'username_too_short',
				__( 'Username must be at least 3 characters long.', 'wppowersuite-lite' )
			);
		}

		if ( strlen( $new_username ) > 60 ) {
			return new \WP_Error(
				'username_too_long',
				__( 'Username cannot exceed 60 characters.', 'wppowersuite-lite' )
			);
		}

		if ( ! validate_username( $new_username ) ) {
			return new \WP_Error(
				'invalid_username',
				__( 'Username contains invalid characters. Username must contain only lowercase letters, numbers, underscores, hyphens, and periods.', 'wppowersuite-lite' )
			);
		}

		if ( $this->usernameExistsForOtherUser( $new_username, $user_id ) ) {
			return new \WP_Error(
				'username_exists',
				sprintf(
					/* translators: %s: Username */
					__( 'The username "%s" is already in use. Please choose a different username.', 'wppowersuite-lite' ),
					esc_html( $new_username )
				)
			);
		}

		if ( $this->isUsernameBlocked( $new_username ) ) {
			return new \WP_Error(
				'username_blocked',
				__( 'This username is not allowed. Please choose a different username.', 'wppowersuite-lite' )
			);
		}

		return true;
	}

	/**
	 * Whether another account already owns this login (case-normalized).
	 */
	private function usernameExistsForOtherUser( string $username, int $user_id ): bool {
		if ( ! username_exists( $username ) ) {
			return false;
		}

		$existing_user = get_user_by( 'login', $username );
		if ( ! $existing_user ) {
			return false;
		}

		return (int) $existing_user->ID !== $user_id;
	}

	/**
	 * Check if Username is Blocked
	 *
	 * Uses WordPress illegal_user_logins (Block Usernames merges into that filter when enabled).
	 *
	 * @since 1.0.0
	 * @param string $username Username to check.
	 * @return bool True if blocked, false otherwise.
	 */
	private function isUsernameBlocked( string $username ): bool {
		$normalized = sanitize_user( trim( $username ), true );
		if ( $normalized === '' ) {
			return false;
		}

		/** @var array<int, string> $illegal */
		$illegal = apply_filters( 'illegal_user_logins', [] );
		if ( $illegal === [] ) {
			return false;
		}

		$needle = strtolower( $normalized );
		foreach ( $illegal as $login ) {
			if ( is_string( $login ) && strtolower( $login ) === $needle ) {
				return true;
			}
		}

		return false;
	}

	/**
	 * Change Username
	 *
	 * Updates the username in the database.
	 *
	 * @since 1.0.0
	 * @param int    $user_id User ID.
	 * @param string $new_username New username.
	 * @return true|\WP_Error True on success, WP_Error on failure.
	 */
	private function changeUsername( int $user_id, string $new_username ): bool|\WP_Error {
		global $wpdb;

		$user = get_userdata( $user_id );
		if ( ! $user ) {
			return new \WP_Error( 'user_not_found', __( 'User not found.', 'wppowersuite-lite' ) );
		}

		$old_username = $user->user_login;

		// Double-check username doesn't exist (race condition protection).
		if ( $this->usernameExistsForOtherUser( $new_username, $user_id ) ) {
			return new \WP_Error(
				'username_exists',
				sprintf(
					/* translators: %s: Username */
					__( 'The username "%s" is already in use. Please choose a different username.', 'wppowersuite-lite' ),
					esc_html( $new_username )
				)
			);
		}

		$result = $wpdb->update(
			$wpdb->users,
			[ 'user_login' => $new_username ],
			[ 'ID' => $user_id ],
			[ '%s' ],
			[ '%d' ]
		);

		if ( $result === false ) {
			if ( $wpdb->last_error ) {
				if ( strpos( $wpdb->last_error, 'Duplicate' ) !== false || strpos( $wpdb->last_error, 'duplicate' ) !== false ) {
					return new \WP_Error(
						'username_exists',
						sprintf(
							/* translators: %s: Username */
							__( 'The username "%s" is already in use. Please choose a different username.', 'wppowersuite-lite' ),
							esc_html( $new_username )
						)
					);
				}
			}
			return new \WP_Error(
				'update_failed',
				__( 'Failed to update username in database.', 'wppowersuite-lite' )
			);
		}

		if ( $user->user_nicename === $old_username ) {
			$wpdb->update(
				$wpdb->users,
				[ 'user_nicename' => $new_username ],
				[ 'ID' => $user_id ],
				[ '%s' ],
				[ '%d' ]
			);
		}

		// Clear all caches
		clean_user_cache( $user_id );
		wp_cache_delete( $user_id, 'users' );
		wp_cache_delete( $old_username, 'userlogins' );
		wp_cache_delete( $new_username, 'userlogins' );

		do_action( 'wp_powersuite_username_changed', $user_id, $old_username, $new_username, get_current_user_id() );

		// Always invalidate stored sessions for the affected account.
		\WP_Session_Tokens::get_instance( $user_id )->destroy_all();

		// Logged-in cookie embeds user_login; refresh auth when self-editing.
		if ( get_current_user_id() === $user_id ) {
			wp_set_current_user( $user_id );
			wp_clear_auth_cookie();
			wp_set_auth_cookie( $user_id, false, is_ssl() );
			wp_set_current_user( $user_id );
		}

		return true;
	}

	/**
	 * Shared POST handler for admin profile and WooCommerce account forms.
	 *
	 * @param callable(string): void $notify_error
	 * @param callable(string): void $notify_success
	 */
	private function processUsernameChangeRequest(
		int $user_id,
		string $nonce_field,
		string $nonce_action_prefix,
		string $username_field,
		callable $notify_error,
		callable $notify_success
	): void {
		if ( RequestSanitizer::requestMethod() !== 'POST' ) {
			return;
		}

		if ( ! isset( $_POST[ $nonce_field ] ) ) {
			return;
		}

		if ( ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST[ $nonce_field ] ) ), $nonce_action_prefix . $user_id ) ) {
			$notify_error( __( 'Security check failed. Please try again.', 'wppowersuite-lite' ) );
			return;
		}

		if ( ! current_user_can( 'edit_user', $user_id ) ) {
			$notify_error( __( 'You do not have permission to change this username.', 'wppowersuite-lite' ) );
			return;
		}

		if ( ! $this->canUserChangeUsername( $user_id ) ) {
			$notify_error( __( 'This username cannot be changed.', 'wppowersuite-lite' ) );
			return;
		}

		if ( ! isset( $_POST[ $username_field ] ) || empty( trim( (string) $_POST[ $username_field ] ) ) ) {
			return;
		}

		$new_username = trim( sanitize_user( wp_unslash( $_POST[ $username_field ] ), true ) );

		$validation_result = $this->validateNewUsername( $new_username, $user_id );
		if ( is_wp_error( $validation_result ) ) {
			$notify_error( $validation_result->get_error_message() );
			return;
		}

		$user = get_userdata( $user_id );
		if ( ! $user ) {
			$notify_error( __( 'User not found.', 'wppowersuite-lite' ) );
			return;
		}

		if ( $user->user_login === $new_username ) {
			return;
		}

		$result = $this->changeUsername( $user_id, $new_username );

		if ( is_wp_error( $result ) ) {
			$notify_error( $result->get_error_message() );
			return;
		}

		$notify_success( $this->buildUsernameChangeSuccessMessage( $new_username, $user_id ) );
	}

	/**
	 * Success copy after a username change (includes login/session guidance).
	 */
	private function buildUsernameChangeSuccessMessage( string $new_username, int $user_id ): string {
		$changed_by_admin = get_current_user_id() > 0 && get_current_user_id() !== $user_id;

		if ( $changed_by_admin ) {
			return sprintf(
				/* translators: 1: New username, 2: Additional guidance sentence. */
				__( 'Username successfully changed to: %1$s. %2$s', 'wppowersuite-lite' ),
				'<strong>' . esc_html( $new_username ) . '</strong>',
				esc_html__( 'The user must sign in with the new username; their active sessions have been signed out.', 'wppowersuite-lite' )
			);
		}

		return sprintf(
			/* translators: 1: New username, 2: Additional guidance sentence. */
			__( 'Username successfully changed to: %1$s. %2$s', 'wppowersuite-lite' ),
			'<strong>' . esc_html( $new_username ) . '</strong>',
			esc_html__( 'Use your new username the next time you sign in. Other active sessions for this account have been signed out.', 'wppowersuite-lite' )
		);
	}

	/**
	 * Check if User Can Change Username
	 *
	 * Determines if a user is allowed to change their username.
	 *
	 * @since 1.0.0
	 * @param int $user_id User ID.
	 * @return bool True if user can change username, false otherwise.
	 */
	private function canUserChangeUsername( int $user_id ): bool {
		if ( is_multisite() && is_super_admin( $user_id ) ) {
			return is_super_admin();
		}

		$current_id = get_current_user_id();
		if ( $current_id === $user_id ) {
			return true;
		}

		return current_user_can( 'edit_users' );
	}

	/**
	 * WooCommerce account edit is the only place we output front-end fields; load assets there only.
	 */
	private function shouldLoadFrontendUsernameChangerAssets(): bool {
		if ( ! is_user_logged_in() ) {
			return false;
		}
		if ( function_exists( 'is_account_page' ) && is_account_page() ) {
			return true;
		}
		return false;
	}

	/**
	 * Transient for admin success/error; scoped to the user who will see the next screen.
	 */
	private function getNoticesTransientKey(): string {
		$uid = (int) get_current_user_id();

		return 'wp_powersuite_username_notices_u' . max( 0, $uid );
	}

	/**
	 * @param string $type success|error|warning|info
	 */
	private function setNotice( string $type, string $message ): void {
		$allowed = [ 'success', 'error', 'warning', 'info' ];
		if ( ! in_array( $type, $allowed, true ) ) {
			$type = 'error';
		}

		$key = $this->getNoticesTransientKey();
		$notices = get_transient( $key );
		if ( ! is_array( $notices ) ) {
			$notices = [];
		}
		$notices[] = [
			'type'    => $type,
			'message' => $message,
		];
		set_transient( $key, $notices, 30 );
	}

	/**
	 * Display Admin Notices
	 *
	 * Displays stored admin notices.
	 *
	 * @since 1.0.0
	 * @return void
	 */
	public function displayAdminNotices(): void {
		$screen = get_current_screen();
		if ( ! $screen || ( $screen->id !== 'profile' && $screen->id !== 'user-edit' ) ) {
			return;
		}

		$key = $this->getNoticesTransientKey();
		$notices = get_transient( $key );
		if ( empty( $notices ) || ! is_array( $notices ) ) {
			return;
		}

		$allowed = [ 'success', 'error', 'warning', 'info' ];

		foreach ( $notices as $notice ) {
			$raw_type = isset( $notice['type'] ) && is_string( $notice['type'] ) ? $notice['type'] : 'info';
			$type = in_array( $raw_type, $allowed, true ) ? $raw_type : 'info';
			$message = isset( $notice['message'] ) ? wp_kses_post( $notice['message'] ) : '';
			if ( '' === $message ) {
				continue;
			}
			?>
			<div class="notice notice-<?php echo esc_attr( $type ); ?> is-dismissible">
				<p><?php echo $message; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></p>
			</div>
			<?php
		}

		delete_transient( $key );
	}

	/**
	 * Hide Default Username Field
	 *
	 * Hides the default WordPress username field when module is enabled.
	 *
	 * @since 1.0.0
	 * @return void
	 */
	public function hideDefaultUsernameField(): void {
		?>
		<?php ob_start(); ?>
			.user-login-wrap,
			tr.user-login-wrap {
				display: none !important;
			}
<?php \WP_PowerSuite\Core\InlineAssets::style( 'wpps-ia-modules-username-changer-module-php-style-1', (string) ob_get_clean() ); ?>
		<?php
	}

	/**
	 * Enqueue Assets
	 *
	 * Enqueues JavaScript for real-time username validation.
	 *
	 * @since 1.0.0
	 * @param string $hook Current admin page hook.
	 * @return void
	 */
	public function enqueueAssets( string $hook ): void {
		if ( $hook !== 'profile.php' && $hook !== 'user-edit.php' ) {
			return;
		}

		wp_enqueue_script( 'jquery' );

		$position_script = "
		jQuery(function($) {
			var \$usernameSection = $('.wp-powersuite-username-changer-section');
			if (!\$usernameSection.length) {
				return;
			}
			var \$target = $('form#your-profile, form#createuser').first();
			if (!\$target.length) {
				return;
			}
			var \$firstSection = \$target.find('h2').first();
			if (\$firstSection.length) {
				\$usernameSection.insertBefore(\$firstSection);
			} else {
				\$target.prepend(\$usernameSection);
			}
		});
		";

		wp_add_inline_script( 'jquery', $position_script . $this->getClientValidationScript( '#new_username', '#username-change-feedback' ) . $this->getSubmitConfirmationScript( '#new_username', 'form#your-profile, form#createuser' ) );
	}

	/**
	 * Add Username Field to WooCommerce My Account Page
	 *
	 * Adds username change field to WooCommerce account edit form.
	 *
	 * @since 1.0.0
	 * @return void
	 */
	public function addWooCommerceUsernameField(): void {
		if ( ! is_user_logged_in() ) {
			return;
		}

		$user_id = get_current_user_id();
		if ( ! current_user_can( 'edit_user', $user_id ) ) {
			return;
		}

		$user = wp_get_current_user();
		if ( ! $user ) {
			return;
		}

		$current_username = $user->user_login;
		$can_change = $this->canUserChangeUsername( $user->ID );

		?>
		<p class="woocommerce-form-row woocommerce-form-row--first form-row form-row-first">
			<label for="current_username_woo"><?php esc_html_e( 'Current Username', 'wppowersuite-lite' ); ?></label>
			<input 
				type="text" 
				id="current_username_woo" 
				name="current_username_woo" 
				value="<?php echo esc_attr( $current_username ); ?>" 
				class="woocommerce-Input woocommerce-Input--text input-text" 
				readonly 
				disabled
			/>
			<span class="description">
				<?php esc_html_e( 'Your current username. This field cannot be edited directly.', 'wppowersuite-lite' ); ?>
			</span>
		</p>

		<p class="woocommerce-form-row woocommerce-form-row--last form-row form-row-last">
			<label for="new_username_woo"><?php esc_html_e( 'New Username', 'wppowersuite-lite' ); ?></label>
			<?php if ( $can_change ) : ?>
				<input 
					type="text" 
					name="new_username_woo" 
					id="new_username_woo" 
					value="" 
					class="woocommerce-Input woocommerce-Input--text input-text" 
					autocomplete="off"
					placeholder="<?php esc_attr_e( 'Enter new username (optional)', 'wppowersuite-lite' ); ?>"
				/>
				<span class="description">
					<?php esc_html_e( 'Enter a new username. Leave blank to keep your current username. Username must be unique and contain only lowercase letters, numbers, underscores, hyphens, and periods.', 'wppowersuite-lite' ); ?>
				</span>
				<span class="description">
					<strong><?php esc_html_e( 'Important:', 'wppowersuite-lite' ); ?></strong>
					<?php esc_html_e( 'Changing your username updates your login name. You must sign in with the new username, active sessions will be signed out, and any pending password-reset links will stop working.', 'wppowersuite-lite' ); ?>
				</span>
				<div id="username-change-feedback-woo" class="wp-powersuite-username-feedback" aria-live="polite" style="margin-top: 10px;"></div>
			<?php else : ?>
				<p class="description">
					<strong><?php esc_html_e( 'Username cannot be changed.', 'wppowersuite-lite' ); ?></strong>
				</p>
			<?php endif; ?>
		</p>
		<?php
		wp_nonce_field( 'wp_powersuite_change_username_woo_' . $user->ID, 'wp_powersuite_username_nonce_woo' );
	}

	/**
	 * Handle Username Change from WooCommerce
	 *
	 * Processes username change from WooCommerce My Account page.
	 *
	 * @since 1.0.0
	 * @param int $user_id User ID.
	 * @return void
	 */
	public function handleWooCommerceUsernameChange( int $user_id ): void {
		$this->processUsernameChangeRequest(
			$user_id,
			'wp_powersuite_username_nonce_woo',
			'wp_powersuite_change_username_woo_',
			'new_username_woo',
			static fn( string $message ) => wc_add_notice( $message, 'error' ),
			static fn( string $message ) => wc_add_notice( $message, 'success' )
		);
	}

	/**
	 * Add Frontend Styles
	 *
	 * Adds CSS styles for frontend profile pages.
	 *
	 * @since 1.0.0
	 * @return void
	 */
	public function addFrontendStyles(): void {
		if ( ! $this->shouldLoadFrontendUsernameChangerAssets() ) {
			return;
		}

		?>
		<?php ob_start(); ?>
			#username-change-feedback,
			#username-change-feedback-woo {
				margin-top: 10px;
				font-size: 13px;
			}
			#username-change-feedback.error,
			#username-change-feedback-woo.error {
				color: #d63638;
			}
			#username-change-feedback.success,
			#username-change-feedback-woo.success {
				color: #00a32a;
			}
<?php \WP_PowerSuite\Core\InlineAssets::style( 'wpps-ia-modules-username-changer-module-php-style-2', (string) ob_get_clean() ); ?>
		<?php
	}

	/**
	 * Add Frontend Scripts
	 *
	 * Adds JavaScript for frontend profile pages.
	 *
	 * @since 1.0.0
	 * @return void
	 */
	public function addFrontendScripts(): void {
		if ( ! $this->shouldLoadFrontendUsernameChangerAssets() ) {
			return;
		}

		wp_enqueue_script( 'jquery' );
		wp_add_inline_script(
			'jquery',
			$this->getClientValidationScript( '#new_username_woo', '#username-change-feedback-woo', true )
				. $this->getSubmitConfirmationScript( '#new_username_woo', 'form.woocommerce-EditAccountForm' )
		);
	}

	/**
	 * Shared client-side format hints (server still validates via validate_username).
	 */
	private function getClientValidationScript( string $input_selector, string $feedback_selector, bool $woo_layout = false ): string {
		$woo_feedback = $woo_layout ? "
				var \$currentFeedback = $(this).closest('p').find('{$feedback_selector}').first();
		" : '';

		return "
		jQuery(function($) {
			var validationTimeout;
			$('{$input_selector}').on('input', function() {
				var newUsername = $(this).val().trim();
				{$woo_feedback}
				var \$feedback = " . ( $woo_layout ? '$currentFeedback' : "$( '{$feedback_selector}' )" ) . ";
				\$feedback.html('').removeClass('error success');
				if (newUsername === '') {
					return;
				}
				clearTimeout(validationTimeout);
				validationTimeout = setTimeout(function() {
					if (newUsername.length < 3) {
						\$feedback.html('<span style=\"color: #d63638;\">Username must be at least 3 characters long.</span>').addClass('error');
						return;
					}
					if (newUsername.length > 60) {
						\$feedback.html('<span style=\"color: #d63638;\">Username cannot exceed 60 characters.</span>').addClass('error');
						return;
					}
					if (!/^[a-z0-9._-]+$/.test(newUsername)) {
						\$feedback.html('<span style=\"color: #d63638;\">Username can only contain lowercase letters, numbers, underscores, hyphens, and periods.</span>').addClass('error');
						return;
					}
					\$feedback.html('<span style=\"color: #00a32a;\">✓ Username format is valid.</span>').addClass('success');
				}, 500);
			});
		});
		";
	}

	/**
	 * Confirm before submitting a profile form with a pending username change.
	 */
	private function getSubmitConfirmationScript( string $input_selector, string $form_selector ): string {
		$message = esc_js(
			__( 'Changing your username updates your login name and signs out other active sessions. Continue?', 'wppowersuite-lite' )
		);

		return "
		jQuery(function($) {
			var \$input = $('{$input_selector}').first();
			if (!\$input.length) {
				return;
			}
			var \$form = \$input.closest('form');
			if (!\$form.length) {
				\$form = $('{$form_selector}').first();
			}
			if (!\$form.length) {
				return;
			}
			\$form.on('submit', function(event) {
				var newUsername = \$input.val().trim();
				if (newUsername === '') {
					return;
				}
				if (!window.confirm('{$message}')) {
					event.preventDefault();
				}
			});
		});
		";
	}
}
