<?php
/**
 * Account linking UI: WooCommerce “Connected accounts” endpoint, shortcode, unlink, password hooks.
 * Runs when any social sign-in module is enabled (not a separate PowerSuite module).
 *
 * @package WP_PowerSuite\OAuth\Accounts
 */

namespace WP_PowerSuite\OAuth\Accounts;

use WP_PowerSuite\Core\OptionStore;
use WP_PowerSuite\Core\OptionStoreModuleSettingsRepository;
use WP_PowerSuite\OAuth\AbstractProvider;
use WP_PowerSuite\OAuth\ModuleLoader;
use WP_PowerSuite\OAuth\OAuthManager;
use WP_PowerSuite\OAuth\UI\SocialLoginStyles;

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Wires the social account management UI and handlers.
 */
final class SocialAccountPanelService {

	public const ENDPOINT = 'wpps-social';

	/** @var array<string, string> slug => connect button label */
	private const PROVIDER_LABELS = [
		'google'   => 'Google',
		'facebook' => 'Facebook',
		'github'   => 'GitHub',
	];

	/** @var string OptionStore module id (legacy) for account-linking policy */
	private const LEGACY_MODULE_ID = 'social-accounts';

	private static bool $registered = false;

	/**
	 * Call once on init when at least one social OAuth module is enabled.
	 */
	public static function register(): void {
		if ( self::$registered || ! ModuleLoader::anySocialActive() ) {
			return;
		}
		self::$registered = true;
		self::retireLegacyModule();
		SocialLoginStyles::ensureAccountPanelStyles();
		( new self() )->addHooks();
	}

	/**
	 * Remove the old “social-accounts” module from the enabled list (functionality is always on with social login).
	 */
	private static function retireLegacyModule(): void {
		$k = 'wpps_social_accounts_merged';
		if ( (string) get_option( $k, '' ) === '1' ) {
			return;
		}
		$os = OptionStore::getInstance();
		if ( OptionStoreModuleSettingsRepository::isModuleEnabled( self::LEGACY_MODULE_ID ) ) {
			$os->disableModule( self::LEGACY_MODULE_ID );
		}
		OptionStoreModuleSettingsRepository::clearCache();
		update_option( $k, '1', false );
	}

	private function addHooks(): void {
		if ( class_exists( 'WooCommerce' ) && $this->accountUiEnabled() ) {
			add_action( 'init', [ $this, 'registerEndpoint' ] );
			add_filter( 'query_vars', [ $this, 'addQueryVar' ] );
			add_filter( 'woocommerce_get_query_vars', [ $this, 'registerWcQueryVar' ] );
			add_filter( 'woocommerce_account_menu_items', [ $this, 'accountMenu' ], 50 );
			add_action( 'woocommerce_account_' . self::ENDPOINT . '_endpoint', [ $this, 'renderAccountPanel' ] );
			// “Edit account” (account details) — same connect/disconnect UI.
			add_action( 'woocommerce_edit_account_form', [ $this, 'renderWooEditAccountPanel' ], 20 );
			// Social-only users do not know WP’s random password; allow first password set without “current” (session + nonce).
			add_action( 'template_redirect', [ $this, 'primeWcFirstTimePasswordPost' ], 1 );
			add_filter( 'check_password', [ $this, 'allowWcFirstTimePasswordCheck' ], 10, 4 );
		}
		// User profile in wp-admin (own profile: connect; other users: read-only or hidden).
		add_action( 'show_user_profile', [ $this, 'renderAdminProfilePanel' ] );
		add_action( 'edit_user_profile', [ $this, 'renderAdminProfilePanel' ] );
		add_action( 'admin_post_wpps_social_unlink', [ $this, 'handleUnlink' ] );
		add_action( 'woocommerce_save_account_details', [ $this, 'onWooPasswordChange' ], 20, 1 );
		add_action( 'personal_options_update', [ $this, 'onAdminProfilePasswordSet' ] );
		add_action( 'edit_user_profile_update', [ $this, 'onAdminProfilePasswordSet' ] );
		add_action( 'after_password_reset', [ $this, 'onAfterPasswordReset' ], 10, 2 );
		add_shortcode( 'wpps_social_accounts', [ $this, 'shortcodePanel' ] );
	}

	public function registerEndpoint(): void {
		if ( ! $this->accountUiEnabled() || ! class_exists( 'WooCommerce' ) ) {
			return;
		}
		add_rewrite_endpoint( self::ENDPOINT, EP_ROOT | EP_PAGES );
		$v = (string) get_option( 'wpps_social_ep_flag', '0' );
		if ( '1' !== $v ) {
			flush_rewrite_rules( false );
			update_option( 'wpps_social_ep_flag', '1', false );
		}
	}

	/**
	 * @param list<string> $v
	 * @return list<string>
	 */
	public function addQueryVar( array $v ): array {
		$v[] = self::ENDPOINT;
		return $v;
	}

	/**
	 * @param array<string, string> $vars
	 * @return array<string, string>
	 */
	public function registerWcQueryVar( array $vars ): array {
		$vars[ self::ENDPOINT ] = self::ENDPOINT;
		return $vars;
	}

	/**
	 * @param array<string, string> $items
	 * @return array<string, string>
	 */
	public function accountMenu( array $items ): array {
		if ( ! $this->accountUiEnabled() || ! class_exists( 'WooCommerce' ) || ! is_user_logged_in() ) {
			return $items;
		}
		$items[ self::ENDPOINT ] = __( 'Connected accounts', 'wp-powersuite' );
		return $items;
	}

	public function renderAccountPanel(): void {
		$this->renderAccountHtml( 'wc-endpoint' );
	}

	/**
	 * WooCommerce “Account details” (edit account) form.
	 */
	public function renderWooEditAccountPanel(): void {
		if ( ! $this->accountUiEnabled() || ! is_user_logged_in() ) {
			return;
		}
		echo '<div class="woocommerce-MyAccount-wpps-connected-accounts" style="margin-top:2em;clear:both;">';
		echo '<h2>' . esc_html__( 'Connected accounts', 'wp-powersuite' ) . '</h2>';
		$this->renderAccountHtml( 'wc-edit-account' );
		echo '</div>';
	}

	/**
	 * wp-admin: Profile and user-edit (own profile only).
	 *
	 * @param \WP_User $user
	 */
	public function renderAdminProfilePanel( $user ): void {
		if ( ! $this->accountUiEnabled() || ! ( $user instanceof \WP_User ) ) {
			return;
		}
		if ( (int) $user->ID !== (int) get_current_user_id() ) {
			return;
		}
		if ( ! current_user_can( 'read' ) ) {
			return;
		}
		echo '<h2 id="wpps-connected-accounts">' . esc_html__( 'Connected accounts', 'wp-powersuite' ) . '</h2>';
		$this->renderAccountHtml( 'admin-profile' );
	}

	public function shortcodePanel(): string {
		ob_start();
		$this->renderAccountHtml( 'wc-endpoint' );
		return (string) ob_get_clean();
	}

	private function accountUiEnabled(): bool {
		$s = AccountLinkSettings::get();
		return (bool) ( $s['show_on_my_account'] ?? true );
	}

	/**
	 * OAuth return URL after a successful “Connect” (state payload).
	 *
	 * @param 'wc-endpoint'|'wc-edit-account'|'admin-profile' $context
	 */
	private function connectReturnUrl( string $context = 'wc-endpoint' ): string {
		$ok = [ 'wpps_social_ok' => 'linked' ];
		if ( 'admin-profile' === $context ) {
			return (string) add_query_arg( $ok, admin_url( 'profile.php' ) );
		}
		if ( 'wc-edit-account' === $context && class_exists( 'WooCommerce' ) && (int) wc_get_page_id( 'myaccount' ) > 0 ) {
			$u = (string) wc_get_account_endpoint_url( 'edit-account' );
			if ( $u !== '' ) {
				return (string) add_query_arg( $ok, $u );
			}
		}
		if ( class_exists( 'WooCommerce' ) && (int) wc_get_page_id( 'myaccount' ) > 0 ) {
			$url = (string) wc_get_account_endpoint_url( self::ENDPOINT );
			if ( is_string( $url ) && $url !== '' ) {
				return (string) add_query_arg( $ok, $url );
			}
		}
		$page = get_queried_object_id();
		if ( $page > 0 && 'page' === get_post_type( $page ) ) {
			$p = get_permalink( $page );
			if ( is_string( $p ) && $p !== '' ) {
				return (string) add_query_arg( $ok, $p );
			}
		}
		return (string) add_query_arg( $ok, home_url( '/' ) );
	}

	/**
	 * @param 'wc-endpoint'|'wc-edit-account'|'admin-profile' $return_context
	 */
	private function renderAccountHtml( string $return_context = 'wc-endpoint' ): void {
		if ( ! is_user_logged_in() ) {
			echo '<p>' . esc_html__( 'You must be logged in to manage connected accounts.', 'wp-powersuite' ) . '</p>';
			return;
		}
		$uid  = (int) get_current_user_id();
		$ids  = SocialAccountStore::getIdentities( $uid );
		$err  = isset( $_GET['wpps_social_error'] ) ? (string) wp_unslash( (string) $_GET['wpps_social_error'] ) : '';
		$note = isset( $_GET['wpps_social_ok'] ) ? sanitize_key( (string) wp_unslash( (string) $_GET['wpps_social_ok'] ) ) : '';
		$rc   = preg_replace( '/[^a-z\-]/', '', $return_context ) ?? $return_context;
		if ( ! in_array( $rc, [ 'wc-endpoint', 'wc-edit-account', 'admin-profile' ], true ) ) {
			$rc = 'wc-endpoint';
		}
		$is_admin = ( 'admin-profile' === $rc );
		$is_woo   = in_array( $rc, [ 'wc-endpoint', 'wc-edit-account' ], true );
		$wrapper  = 'wpps-social-accounts';
		if ( $is_admin ) {
			$wrapper .= ' wpps-social-accounts--admin';
		} elseif ( $is_woo ) {
			$wrapper .= ' wpps-social-accounts--woo';
		}
		$table_class = 'wpps-social-accounts-table';
		if ( $is_admin ) {
			$table_class .= ' widefat striped';
		} else {
			$table_class .= ' shop_table shop_table_responsive';
		}
		$btn_class = $is_woo ? 'button woocommerce-button' : 'button';

		?>
		<div class="<?php echo esc_attr( $wrapper ); ?>" data-user-id="<?php echo esc_attr( (string) $uid ); ?>" data-wpps-return="<?php echo esc_attr( $rc ); ?>">
			<?php if ( $err !== '' ) : ?>
				<div class="<?php echo $is_admin ? 'notice notice-error' : 'woocommerce-error'; ?>" role="alert"><p><?php echo esc_html( rawurldecode( $err ) ); ?></p></div>
			<?php endif; ?>
			<?php if ( 'unlinked' === $note || 'linked' === $note ) : ?>
				<div class="<?php echo $is_admin ? 'notice notice-success' : 'woocommerce-message'; ?>" role="status">
					<p><?php echo ( 'linked' === $note ) ? esc_html__( 'Provider connected successfully.', 'wp-powersuite' ) : esc_html__( 'Provider disconnected.', 'wp-powersuite' ); ?></p>
				</div>
			<?php endif; ?>
			<p class="description"><?php esc_html_e( 'Connect additional sign-in methods or remove ones you no longer use. You must always keep at least one way to sign in.', 'wp-powersuite' ); ?></p>
			<table class="<?php echo esc_attr( $table_class ); ?>">
				<thead>
					<tr>
						<th><?php esc_html_e( 'Provider', 'wp-powersuite' ); ?></th>
						<th><?php esc_html_e( 'Status', 'wp-powersuite' ); ?></th>
						<th class="actions"><?php esc_html_e( 'Actions', 'wp-powersuite' ); ?></th>
					</tr>
				</thead>
				<tbody>
				<?php
				$provs = OAuthManager::getProviders();
				ksort( $provs );
				foreach ( $provs as $slug => $provider ) {
					if ( ! ( $provider instanceof AbstractProvider ) ) {
						continue;
					}
					$label     = self::PROVIDER_LABELS[ $slug ] ?? ucfirst( (string) $slug );
					$slug      = sanitize_key( (string) $slug );
					$connected = isset( $ids[ $slug ] );
					$unlink    = $connected ? LoginMethodGuard::canUnlink( $uid, $slug ) : [ 'allowed' => false, 'message' => '' ];
					echo '<tr>';
					echo '<td data-title="' . esc_attr__( 'Provider', 'wp-powersuite' ) . '"><strong>' . esc_html( $label ) . '</strong>';
					if ( $connected && ! empty( $ids[ $slug ]['email'] ) ) {
						echo '<br><span class="description">' . esc_html( (string) $ids[ $slug ]['email'] ) . '</span>';
					}
					echo '</td>';
					echo '<td data-title="' . esc_attr__( 'Status', 'wp-powersuite' ) . '">';
					echo $connected ? esc_html__( 'Connected', 'wp-powersuite' ) : esc_html__( 'Not connected', 'wp-powersuite' );
					echo '</td><td class="actions">';
					if ( $connected ) {
						if ( $unlink['allowed'] ) {
							echo '<form method="post" action="' . esc_url( admin_url( 'admin-post.php' ) ) . '" class="wpps-social-accounts-unlink-form">';
							echo '<input type="hidden" name="action" value="wpps_social_unlink" />';
							echo '<input type="hidden" name="provider" value="' . esc_attr( $slug ) . '" />';
							echo '<input type="hidden" name="wpps_social_return" value="' . esc_attr( $rc ) . '" />';
							wp_nonce_field( 'wpps_social_unlink', 'wpps_social_unlink' );
							echo '<button type="submit" class="' . esc_attr( $btn_class ) . '">' . esc_html__( 'Disconnect', 'wp-powersuite' ) . '</button></form>';
						} else {
							echo '<span class="description">' . esc_html__( 'See note below', 'wp-powersuite' ) . '</span>';
						}
					} elseif ( AccountLinkSettings::isLinkingEnabled() ) {
						$ret  = $this->connectReturnUrl( $rc );
						$url  = $provider->getAuthorizationUrl( $ret, (int) $uid );
						if ( is_string( $url ) && $url !== '' ) {
							echo '<a class="' . esc_attr( $btn_class ) . '" href="' . esc_url( $url ) . '">' . esc_html(
								sprintf(
									/* translators: %s: provider name */
									__( 'Connect %s', 'wp-powersuite' ),
									$label
								)
							) . '</a>';
						} else {
							echo '<span class="description">—</span>';
						}
					} else {
						echo '<span class="description">—</span>';
					}
					echo '</td></tr>';
					if ( $connected && ! $unlink['allowed'] ) {
						$this->renderUnlinkHelpRow( $unlink, $rc, $is_admin );
					}
				}
				?>
				</tbody>
			</table>
		</div>
		<?php
	}

	public function handleUnlink(): void {
		if ( ! is_user_logged_in() ) {
			wp_safe_redirect( wp_login_url() );
			exit;
		}
		// phpcs:ignore WordPress.Security.NonceVerification.Missing
		if ( ! isset( $_POST['wpps_social_unlink'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( (string) $_POST['wpps_social_unlink'] ) ), 'wpps_social_unlink' ) ) {
			wp_die( esc_html__( 'Invalid request.', 'wp-powersuite' ) );
		}
		$uid      = (int) get_current_user_id();
		$provider = isset( $_POST['provider'] ) ? sanitize_key( (string) wp_unslash( (string) $_POST['provider'] ) ) : '';
		$ret_ctx  = isset( $_POST['wpps_social_return'] ) ? (string) wp_unslash( (string) $_POST['wpps_social_return'] ) : '';
		$ret_ctx  = preg_replace( '/[^a-z\-]/', '', $ret_ctx ) ?? '';
		if ( ! in_array( $ret_ctx, [ 'wc-endpoint', 'wc-edit-account', 'admin-profile' ], true ) ) {
			$ret_ctx = 'wc-endpoint';
		}
		$ok       = LoginMethodGuard::canUnlink( $uid, $provider );
		if ( ! $ok['allowed'] ) {
			$this->redirectWithMsg( 'error', $ok['message'], $ret_ctx );
		}
		$meta = SocialAccountStore::legacyKeyForProvider( $provider );
		SocialAccountStore::removeProvider( $uid, $provider, $meta );
		$this->redirectWithMsg( 'unlinked', '', $ret_ctx );
	}

	/**
	 * @param 'error'|'unlinked'|'linked' $code
	 * @param 'wc-endpoint'|'wc-edit-account'|'admin-profile' $return_context
	 */
	private function redirectWithMsg( string $code, string $message = '', string $return_context = 'wc-endpoint' ): void {
		$base = $this->getPanelUrl( $return_context );
		if ( 'error' === $code ) {
			$u = add_query_arg( 'wpps_social_error', rawurlencode( $message ), $base );
		} else {
			$u = add_query_arg( 'wpps_social_ok', $code, $base );
		}
		wp_safe_redirect( $u );
		exit;
	}

	/**
	 * @param 'wc-endpoint'|'wc-edit-account'|'admin-profile' $return_context
	 */
	private function getPanelUrl( string $return_context = 'wc-endpoint' ): string {
		if ( 'admin-profile' === $return_context && is_user_logged_in() ) {
			return (string) admin_url( 'profile.php' );
		}
		if ( 'wc-edit-account' === $return_context && class_exists( 'WooCommerce' ) && (int) wc_get_page_id( 'myaccount' ) > 0 && is_user_logged_in() ) {
			$url = (string) wc_get_account_endpoint_url( 'edit-account' );
			if ( $url !== '' ) {
				return $url;
			}
		}
		if ( class_exists( 'WooCommerce' ) && (int) wc_get_page_id( 'myaccount' ) > 0 && is_user_logged_in() ) {
			$url = wc_get_account_endpoint_url( self::ENDPOINT );
			if ( is_string( $url ) && $url !== '' ) {
				return $url;
			}
		}
		return home_url( '/' );
	}

	/**
	 * Full-width row when disconnect is blocked (admin profile + Woo My Account).
	 *
	 * @param array{allowed: bool, message: string, reason?: string} $unlink
	 * @param 'wc-endpoint'|'wc-edit-account'|'admin-profile'      $return_context
	 */
	private function renderUnlinkHelpRow( array $unlink, string $return_context, bool $is_admin ): void {
		echo '<tr class="wpps-social-accounts-help-row"><td colspan="3" class="wpps-social-accounts-help-cell">';
		if ( $is_admin ) {
			echo '<div class="notice notice-warning inline wpps-social-cannot-unlink"><p>';
			$this->renderCannotUnlinkHelp( $unlink, $return_context );
			echo '</p></div>';
		} else {
			echo '<div class="woocommerce-info wpps-social-cannot-unlink">';
			$this->renderCannotUnlinkHelp( $unlink, $return_context );
			echo '</div>';
		}
		echo '</td></tr>';
	}

	/**
	 * In-page help when the last sign-in method would be removed.
	 *
	 * @param array{allowed: bool, message: string, reason?: string} $unlink
	 * @param 'wc-endpoint'|'wc-edit-account'|'admin-profile'      $return_context
	 */
	private function renderCannotUnlinkHelp( array $unlink, string $return_context ): void {
		$message = (string) ( $unlink['message'] ?? '' );
		$reason  = (string) ( $unlink['reason'] ?? '' );

		if ( LoginMethodGuard::REASON_LAST_LOGIN_METHOD === $reason ) {
			if ( 'admin-profile' === $return_context ) {
				echo esc_html__( 'Add another sign-in method or set a password on this page before disconnecting this one.', 'wp-powersuite' ) . ' ';
				echo '<a href="#pass1" class="wpps-social-goto-password">' . esc_html__( 'Go to password fields', 'wp-powersuite' ) . '</a>. ';
				esc_html_e( 'Enter a new password, click Update Profile, then return here to disconnect.', 'wp-powersuite' );
				return;
			}
			if ( 'wc-edit-account' === $return_context ) {
				echo esc_html__( 'Add another sign-in method or set a password in the fields above before disconnecting this one.', 'wp-powersuite' ) . ' ';
				echo '<a href="#password_1">' . esc_html__( 'Go to password fields', 'wp-powersuite' ) . '</a>. ';
				echo '<span class="description">';
				esc_html_e( 'Leave “Current password” empty, enter your new password twice, then save.', 'wp-powersuite' );
				echo '</span>';
				return;
			}
			echo esc_html__( 'Add another sign-in method or set a password in your account details before disconnecting this one.', 'wp-powersuite' ) . ' ';
			$set_url   = $this->getSetPasswordUrl( $return_context );
			$link_text = ( class_exists( 'WooCommerce' ) && (int) wc_get_page_id( 'myaccount' ) > 0 )
				? __( 'Open Account details', 'wp-powersuite' )
				: __( 'Set a password', 'wp-powersuite' );
			echo '<a href="' . esc_url( $set_url ) . '">' . esc_html( $link_text ) . '</a>';
			if ( class_exists( 'WooCommerce' ) && (int) wc_get_page_id( 'myaccount' ) > 0 ) {
				echo '<br><span class="description">';
				esc_html_e( 'There, leave “Current password” empty, enter your new password twice, then save.', 'wp-powersuite' );
				echo '</span>';
			}
			return;
		}

		echo esc_html( $message ) . ' ';
		if ( 'admin-profile' === $return_context ) {
			echo '<a href="#pass1" class="wpps-social-goto-password">' . esc_html__( 'Go to password fields', 'wp-powersuite' ) . '</a>';
		} elseif ( 'wc-edit-account' === $return_context ) {
			echo '<a href="#password_1">' . esc_html__( 'Go to password fields', 'wp-powersuite' ) . '</a>';
		} else {
			$set_url = $this->getSetPasswordUrl( $return_context );
			echo '<a href="' . esc_url( $set_url ) . '">' . esc_html__( 'Set a password', 'wp-powersuite' ) . '</a>';
		}
	}

	/**
	 * URL where the user can choose a known password (Woo “Account details” or wp-admin profile).
	 *
	 * @param 'wc-endpoint'|'wc-edit-account'|'admin-profile' $return_context
	 */
	private function getSetPasswordUrl( string $return_context ): string {
		if ( class_exists( 'WooCommerce' ) && (int) wc_get_page_id( 'myaccount' ) > 0 ) {
			$u = (string) wc_get_account_endpoint_url( 'edit-account' );
			if ( $u !== '' ) {
				return $u;
			}
		}
		if ( is_user_logged_in() ) {
			return (string) admin_url( 'profile.php#pass1' );
		}
		$base = (string) ( function_exists( 'wp_login_url' ) ? wp_login_url( home_url( '/' ) ) : home_url( '/' ) );
		return (string) ( function_exists( 'wp_lostpassword_url' ) ? wp_lostpassword_url( $base ) : $base );
	}

	/**
	 * WooCommerce insists on a “current password” when changing the password; social-only users never knew the random WP password.
	 * Before WC runs, copy the new password into the current field so validation runs; {@see allowWcFirstTimePasswordCheck} approves that one check.
	 */
	public function primeWcFirstTimePasswordPost(): void {
		if ( empty( $_POST['action'] ) || 'save_account_details' !== $_POST['action'] ) {
			return;
		}
		if ( ! is_user_logged_in() || ! class_exists( 'WooCommerce' ) ) {
			return;
		}
		$uid = (int) get_current_user_id();
		if ( $uid <= 0 || ! LoginMethodGuard::canSetFirstWcPasswordWithoutCurrent( $uid ) ) {
			return;
		}
		// phpcs:ignore WordPress.Security.NonceVerification.Missing -- WC verifies in its handler.
		$cur = isset( $_POST['password_current'] ) ? (string) wp_unslash( (string) $_POST['password_current'] ) : '';
		if ( $cur !== '' ) {
			return;
		}
		// phpcs:ignore WordPress.Security.NonceVerification.Missing
		$p1 = isset( $_POST['password_1'] ) ? (string) wp_unslash( (string) $_POST['password_1'] ) : '';
		// phpcs:ignore WordPress.Security.NonceVerification.Missing
		$p2 = isset( $_POST['password_2'] ) ? (string) wp_unslash( (string) $_POST['password_2'] ) : '';
		if ( $p1 === '' || $p1 !== $p2 || strlen( $p1 ) < 6 ) {
			return;
		}
		$_POST['password_current'] = $p1;
	}

	/**
	 * Approve wp_check_password when WC compares the mirrored “current” to the old hash for first-time password set (session + nonce already prove identity).
	 *
	 * @param bool        $check    Whether the passwords match.
	 * @param string      $password The plaintext password to check.
	 * @param string      $hash     The hashed password to check against.
	 * @param int|string $user_id   User ID.
	 */
	public function allowWcFirstTimePasswordCheck( $check, $password, $hash, $user_id ): bool {
		if ( $check || ! is_string( $password ) || $password === '' ) {
			return (bool) $check;
		}
		$uid = is_scalar( $user_id ) ? (int) $user_id : 0;
		if ( $uid <= 0 || (int) get_current_user_id() !== $uid ) {
			return $check;
		}
		// phpcs:ignore WordPress.Security.NonceVerification.Missing
		if ( empty( $_POST['action'] ) || 'save_account_details' !== $_POST['action'] ) {
			return $check;
		}
		$nonce = isset( $_REQUEST['save-account-details-nonce'] ) ? (string) wp_unslash( (string) $_REQUEST['save-account-details-nonce'] ) : '';
		if ( $nonce === '' || ! wp_verify_nonce( $nonce, 'save_account_details' ) ) {
			return $check;
		}
		if ( ! LoginMethodGuard::canSetFirstWcPasswordWithoutCurrent( $uid ) ) {
			return $check;
		}
		// phpcs:ignore WordPress.Security.NonceVerification.Missing
		$p1 = isset( $_POST['password_1'] ) ? (string) wp_unslash( (string) $_POST['password_1'] ) : '';
		if ( $p1 === '' || $p1 !== $password ) {
			return $check;
		}
		$user = get_userdata( $uid );
		if ( ! $user || (string) $hash !== (string) $user->user_pass ) {
			return $check;
		}
		return true;
	}

	/**
	 * @param int $user_id
	 */
	public function onWooPasswordChange( $user_id ): void {
		$user_id = (int) $user_id;
		if ( $user_id <= 0 ) {
			return;
		}
		// phpcs:ignore WordPress.Security.NonceVerification.Missing
		$pass1 = isset( $_POST['password_1'] ) ? (string) wp_unslash( (string) $_POST['password_1'] ) : '';
		if ( $pass1 === '' || strlen( $pass1 ) < 6 ) {
			return;
		}
		LoginMethodGuard::markPasswordReady( $user_id );
	}

	/**
	 * Marks a password as “known to the user” when saved from the WordPress profile / user edit screen.
	 *
	 * @param int $user_id
	 */
	public function onAdminProfilePasswordSet( $user_id ): void {
		$user_id = (int) $user_id;
		if ( $user_id <= 0 ) {
			return;
		}
		// phpcs:ignore WordPress.Security.NonceVerification.Missing
		if ( ! isset( $_POST['pass1'] ) || ! is_string( $_POST['pass1'] ) ) {
			return;
		}
		$pass1 = (string) wp_unslash( $_POST['pass1'] );
		if ( $pass1 === '' || strlen( $pass1 ) < 6 ) {
			return;
		}
		LoginMethodGuard::markPasswordReady( $user_id );
	}

	/**
	 * @param \WP_User $user
	 */
	public function onAfterPasswordReset( $user, $new_password ): void {
		if ( $user instanceof \WP_User && (string) $new_password !== '' ) {
			LoginMethodGuard::markPasswordReady( (int) $user->ID );
		}
	}
}
