/**
 * Copyright © 2024 Nevis Security AG. All rights reserved.
 */

import type { PasswordChangeRecoverableCustomValidationError } from '../../error/password/change/PasswordChangeRecoverableCustomValidationError';
import type { PasswordEnrollmentCustomValidationError } from '../../error/password/enrollment/PasswordEnrollmentCustomValidationError';

/**
 * The object defining whether the password provided by a user during enrollment
 * or when changing is valid.
 */
export abstract class PasswordPolicy {
	/**
	 * Default constructor for {@link PasswordPolicy}.
	 *
	 * @returns an {@link PasswordPolicy} instance.
	 */
	static create(): PasswordPolicy {
		return new PasswordPolicyImpl();
	}

	/**
	 * Performs validation of the password for enrollment during a registration.
	 *
	 * If validation fails, the implementation must invoke the provided `onError`
	 * with the error. The error will be the one returned by the
	 * {@link PasswordEnrollmentContext.lastRecoverableError} property.
	 *
	 * The implementation must guarantee that, one (and only one) of `onSuccess`
	 * and `onError` is invoked, and that the one invoked is invoked only once.
	 *
	 * Synchronous implementation example that requires password to have at least
	 * 8 different characters:
	 * ```ts
	 *  validatePasswordForEnrollment(
	 *      _password: string,
	 *      onSuccess: () => void,
	 *      _onError: (error: PasswordEnrollmentCustomValidationError) => void
	 *  ): void {
	 *      if(isAtLeast8CharacterLong(password)) {
	 *          const error = new PasswordEnrollmentCustomValidationError(
	 *              "The password has less than 8 characters."
	 *          );
	 *          onError(error);
	 *      } else {
	 *          onSuccess();
	 *      }
	 *  }
	 * ```
	 *
	 * @param password the password to be validated.
	 * @param onSuccess the callback to invoke if the validation is successful.
	 * @param onError the callback to invoke with error if the validation fails.
	 */
	abstract validatePasswordForEnrollment(
		password: string,
		onSuccess: () => void,
		onError: (error: PasswordEnrollmentCustomValidationError) => void
	): void;

	/**
	 * Performs validation of the password during a {@link PasswordChange} operation.
	 *
	 * If validation fails, the implementation must invoke the provided `onError`
	 * with the error. The error will be the one returned by the
	 * {@link PasswordChangeContext.lastRecoverableError} property.
	 *
	 * The implementation must guarantee that, one (and only one) of `onSuccess`
	 * and `onError` is invoked, and that the one invoked is invoked only once.
	 *
	 * Synchronous implementation example that requires the password to be the same as
	 * a confirmation password provided in another field:
	 * ```ts
	 *  validatePasswordForPasswordChange(
	 *      _password: string,
	 *      onSuccess: () => void,
	 *      _onError: (error: PasswordChangeRecoverableCustomValidationError) => void
	 *  ): void {
	 *      if(isAtLeast8CharacterLong(password)) {
	 *          const error = new PasswordChangeRecoverableCustomValidationError(
	 *              "The password has less than 8 characters."
	 *          );
	 *          onError(error);
	 *      } else {
	 *          onSuccess();
	 *      }
	 *  }
	 * ```
	 *
	 * @param password the password to be validated.
	 * @param onSuccess the callback to invoke if the validation is successful.
	 * @param onError the callback to invoke with error if the validation fails.
	 */
	abstract validatePasswordForPasswordChange(
		password: string,
		onSuccess: () => void,
		onError: (error: PasswordChangeRecoverableCustomValidationError) => void
	): void;
}

export class PasswordPolicyImpl extends PasswordPolicy {
	constructor() {
		super();
	}

	validatePasswordForEnrollment(
		_password: string,
		onSuccess: () => void,
		// eslint-disable-next-line  @typescript-eslint/no-unused-vars
		_onError: (error: PasswordEnrollmentCustomValidationError) => void
	): void {
		onSuccess();
	}

	validatePasswordForPasswordChange(
		_password: string,
		onSuccess: () => void,
		// eslint-disable-next-line  @typescript-eslint/no-unused-vars
		_onError: (error: PasswordChangeRecoverableCustomValidationError) => void
	): void {
		onSuccess();
	}
}
