import { AbstractControl, ValidationErrors, ValidatorFn } from '@angular/forms';
import * as _moment from 'moment';

export class ValidatorsHelper {
  static urlValidator(protocols: string[]): ValidatorFn {
    return (control: AbstractControl): ValidationErrors | null => {
      {
        try {
          const url = new URL(control.value);
          if (protocols && !protocols.includes(url.protocol.replace(':', ''))) {
            return {invalidUrl: true};
          }
          return null;
        } catch (_) {
          return {invalidUrl: true};
        }
      }
    }
  }

  static stepValueValidator(step: number): ValidatorFn {
    return (control: AbstractControl): ValidationErrors | null => {
      if (control.value % step > 0) {
        return {step: step};
      }
      return null;
    }
  }

  static nonZeroValidator(control: AbstractControl): ValidationErrors | null {
    return control.value === 0 ? {nonZero: true} : null;
  }

  static requiredIntegerValidator(control: AbstractControl): ValidationErrors | null {
    return !Number.isInteger(control.value) ? {integerRequired: true} : null;
  }

  static requiredNumericValueValidator(control: AbstractControl): ValidationErrors | null {
    if (typeof control.value !== 'number') {
      if (Number.parseFloat(control.value) == control.value) {
        return null;
      }
      return {
        numericRequired: true
      };
    }
    return null;
  }

  static requiredObjectValidator(control: AbstractControl): ValidationErrors | null {
    return typeof control.value !== 'object' || control.value === null ? {objectRequired: true} : null;
  }

  static requiredCustomFieldValidator(choices): ValidatorFn {
    return (control: AbstractControl): ValidationErrors | null => {
      const value = control.value;
      if (value !== null && value !== '' && value !== undefined) {
        const validChoice = choices.find(choice => choice.value.toString() === value.toString());
        return validChoice ? null : {objectRequired: true};
      } else {
        return null;
      }
    }
  }

  static objectOrEmptyValidator(control: AbstractControl): ValidationErrors | null {
    if (control.value === null || control.value === '') {
      return null;
    }
    return typeof control.value !== 'object' ? {invalidSelection: true} : null;
  }

  static internationalPhoneNumber(control: AbstractControl): ValidationErrors | null {
    if (control.value === null || control.value === '') {
      return null;
    }
    return control.value.startsWith('+') ? null : {invalidInternationalPhone: true};
  }

  static timeValidator(timeFormat, timeExample): ValidatorFn {
    return (control: AbstractControl): ValidationErrors | null => {
      if (!control.value) {
        return null;
      }
      const momentObj = _moment(control.value, timeFormat);
      if (!momentObj.isValid()) {
        return {
          invalidTime: true,
          example: timeExample,
        };
      }
      return null;
    };
  }
}
