import { AbstractControl, ValidatorFn, Validators } from '@angular/forms';
import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model';
import { isNullOrUndefined } from '@app/utilities/enhancers/utils';

export function BackendErrorValidator(errorModel: ValidationErrorModel, propertyName: string): ValidatorFn {
	return (control: AbstractControl): { [key: string]: any } => {
		const error: string = errorModel.getError(propertyName);
		return error ? { 'backendError': { message: error } } : null;
	};
}

export function E164PhoneValidator(): ValidatorFn {
	return Validators.pattern('^\\+?[1-9]\\d{1,14}$');
}

// Getter is required because the index of each element is not fixed (array does not always follow LIFO)
export function BackendArrayErrorValidator(errorModel: ValidationErrorModel, propertyNameGetter: () => string): ValidatorFn {
	return (control: AbstractControl): { [key: string]: any } => {
		const error: string = errorModel.getError(propertyNameGetter());
		return error ? { 'backendError': { message: error } } : null;
	};
}

export function CustomErrorValidator(errorModel: ValidationErrorModel, propertyNames: string[]): ValidatorFn {
	return (control: AbstractControl): { [key: string]: any } => {
		const error: string = errorModel.getErrors(propertyNames);
		return error ? { 'customError': { message: error } } : null;
	};
}

export function DateValidator(): ValidatorFn {
	return (control: AbstractControl): { [key: string]: any } => {
		if (control.value) {
			const dateString: string[] = control.value.split('-');
			const yearString = dateString.length > 0 ? dateString[0].replace(/_/g, '') : null;
			const monthString = dateString.length > 1 ? dateString[1].replace(/_/g, '') : null;
			const dayString = dateString.length > 2 ? dateString[2].replace(/_/g, '') : null;
			let yearParsed: number = null;
			let monthParsed: number = null;
			let dayParsed: number = null;

			if (!isNullOrUndefined(yearString) && yearString.length === 4 && Number(yearString) !== NaN) {
				yearParsed = Number(yearString);
			}
			if (!isNullOrUndefined(monthString) && monthString.length > 0 && Number(monthString) !== NaN) {
				monthParsed = Number(monthString);
			}
			if (!isNullOrUndefined(dayString) && dayString.length > 0 && Number(dayString) !== NaN) {
				dayParsed = Number(dayString);
			}

			if ((dayParsed && (!monthParsed || !yearParsed)) || (monthParsed && !yearParsed) || !yearParsed) {
				return { 'invalidDate': true };
			}

			const current_date = new Date();
			yearParsed = yearParsed ? yearParsed : current_date.getFullYear();
			monthParsed = monthParsed ? monthParsed - 1 : current_date.getMonth();
			dayParsed = dayParsed ? dayParsed : 1;

			//due to autocorrection of Date objects
			const d = new Date(yearParsed, monthParsed, dayParsed);
			if (d.getFullYear() === yearParsed && d.getMonth() === monthParsed && d.getDate() === dayParsed) {
				return null;
			}
			return { 'invalidDate': true };
		}
		return null;
	};
}

export function DateFromToValidator(): ValidatorFn {
	return (control: AbstractControl): { [key: string]: any } => {
		if (control.get('fromTime').value && control.get('toTime').value) {
			const fromDate = new Date(control.get('fromTime').value);
			const toDate = new Date(control.get('toTime').value);
			if (fromDate <= toDate) { return null; }
			return { 'invalidFromToDate': true };
		}
		return null;
	};
}

export function EmailMatchValidator(): ValidatorFn {
	return (control: AbstractControl): { [key: string]: any } => {
		return control.get('email').value === control.get('emailConfirm').value ? null : { 'emailMismatch': true };
	};
}

export function PasswordMatchValidator(passwordControlName: string, repeatPasswordControlName: string): ValidatorFn {
	return (control: AbstractControl): { [key: string]: any } => {
		const passwordControl = control.get(passwordControlName);
		const passwordRepeatControl = control.get(repeatPasswordControlName);

		if (passwordControl && passwordControl.value && passwordRepeatControl && passwordRepeatControl.value && passwordControl.value !== passwordRepeatControl.value) {
			return { 'passwordMismatch': true };
		}
		return null;
	};
}
