import { getCountryCallingCode, parsePhoneNumber } from '../../../polyfill/libphonenumber';
import { InternalFormFieldValidationRule } from './internal-form-field-validation-rule.abstract';
/**
 * A rule that checks if it's a valid phone number
 *
 * @augments {InternalFormFieldValidationRule<string>}
 */
export class ValidPhoneNumberRule extends InternalFormFieldValidationRule {
  constructor(countryCodeGetter, emptyValueEnabled = false) {
    super();
    this.countryCodeGetter = countryCodeGetter;
    this.emptyValueEnabled = emptyValueEnabled;
    /**
     * Generate an invalid result
     *
     * @param {string} message Error message
     * @returns {EvaluateResultTranslation['message']} invalid validation result
     */
    this.invalidResult = (message) => ({
      isValid: false,
      message,
    });
    /**
     * Generate a valid result
     *
     * @returns {EvaluateResultTranslation} invalid validation result
     */
    this.validResult = () => ({
      isValid: true,
      message: '',
    });
  }
  /**
   * It checks if the phone number is valid.
   *
   * @param {string} input - The input value to be evaluated.
   * @returns {EvaluateResultTranslation} an object with two properties: isValid and message.
   */
  evaluate(input) {
    return this.isValidPhoneNumberForCountry(input, this.countryCodeGetter());
  }
  /**
   * If the input is accepted and the status is not disabled and visible, then return true
   *
   * @param {unknown} input - The input to be evaluated.
   * @param {FormFieldStatusMeta} [status] - FormFieldStatusMeta
   * @returns {boolean} The return value is a boolean that indicates whether the input can be evaluated.
   */
  canEvaluate(input, status) {
    return status
      ? this.isAcceptedInputType(input) && !status.disabled && status.visible
      : this.isAcceptedInputType(input);
  }
  /**
   * If the field is not disabled, visible, and has been touched or modified, then show the error
   *
   * @param {FormFieldStatusMeta} status - FormFieldStatusMeta
   * @returns {boolean} A boolean value.
   */
  shouldShowError(status) {
    return !status.disabled && status.visible && (status.touched || status.modified);
  }
  /**
   * The function `isAcceptedInputType` checks if the input is a string and not equal to a specific
   * country calling code.
   *
   * @param {unknown} input - The `input` parameter is of type `unknown`, which means it can be any type.
   * In the `isAcceptedInputType` function, it checks if the `input` is a string and not equal to a
   * specific country calling code.
   * @returns {boolean} a boolean value based on whether the input is a string and not equal to the country calling
   * code with a plus sign appended to it.
   * The input is empty mean the component property `emptyValueEnabled` is true, we should not validate the input.
   */
  isAcceptedInputType(input) {
    const shouldSkipEmptyValueCheck = this.emptyValueEnabled && input === '';
    return (typeof input === 'string' &&
      input !== `+${getCountryCallingCode(this.countryCodeGetter())}` &&
      !shouldSkipEmptyValueCheck);
  }
  /**
   * The function `isValidPhoneNumberForCountry` validates a phone number for a specific country code.
   *
   * @param {string} number - The `number` parameter is a string representing a phone number that you
   * want to validate.
   * @param {VegaCountryCode} countryCode - The `countryCode` parameter in the `isValidPhoneNumberForCountry`
   * function is of type `VegaCountryCode`. It is used to specify the country for which the phone number
   * should be validated. The function attempts to parse the input phone number with the specified
   * country code and performs validation checks to determine if the
   * @returns {EvaluateResultTranslation} The `isValidPhoneNumberForCountry` function returns an `EvaluateResult` object. This object
   * contains information about whether the phone number provided is valid for the specified country
   * code. The function may return a valid result if the phone number is valid for the country code, an
   * invalid result if the phone number is not valid or does not belong to the specified country, or an
   * error message if an exception occurs during
   */
  isValidPhoneNumberForCountry(number, countryCode) {
    try {
      const phoneNumber = parsePhoneNumber(number, {
        defaultCountry: countryCode,
        // Demand that the entire input string must be a phone number.
        // Otherwise, it would "extract" a phone number from an input string.
        extract: false,
      });
      if (phoneNumber.country && phoneNumber.country !== countryCode) {
        return this.invalidResult({
          key: 'Phone number is valid but it belongs to country {0}, not country {1}',
          args: [phoneNumber.country, countryCode],
        });
      }
      if (!phoneNumber.isValid()) {
        return this.invalidResult(`Phone number is not valid`);
      }
      return this.validResult();
    }
    catch (_a) {
      return this.invalidResult(`Phone number is not valid`);
    }
  }
}
