import { AbstractControl, AsyncValidatorFn, ValidationErrors } from '@angular/forms';
import { catchError, map, Observable, of } from 'rxjs';

export interface UniqueValueValidatorOptions<T> {
  avoidValues?: T[];
  errorKey?: string;
}

export type UniqueValueFetcher<T> = (value: T, avoidValues: T[]) => Observable<boolean>;

export const uniqueValueValidator = <T = string>(
  fetcher: UniqueValueFetcher<T>,
  options: UniqueValueValidatorOptions<T> = {},
): AsyncValidatorFn => {
  const avoidValues = options.avoidValues ?? [];
  const errorKey = options.errorKey ?? 'uniqueValue';

  return (control: AbstractControl): Observable<ValidationErrors | null> => {
    const value = control.value as T;
    if (value === null || value === undefined || (typeof value === 'string' && value === '')) {
      return of(null);
    }

    return fetcher(value, avoidValues).pipe(
      map((isAvailable) => (isAvailable ? null : { [errorKey]: true })),
      catchError((error) => {
        console.error(`[uniqueValueValidator] fetcher error:`, error);
        return of(null);
      }),
    );
  };
};
