import { TConfig, TContext } from "./types.js";

export const isFunc = (fn: any) => typeof fn === "function";
export const isString = (str: any): str is string => typeof str === "string";
export const isNumber = (num: any): num is number => typeof num === "number";
export const isObject = (obj: any): obj is object => typeof obj === "object";
export const isArray = (arr: any): arr is any[] => Array.isArray(arr);

export const debounce = <T extends unknown[]>(
  func: (...args: T) => void,
  delay: number
) => {
  let timerId: number | null = null;

  return (...args: T) => {
    if (timerId) {
      window.clearTimeout(timerId);
    }

    return new Promise<unknown>((resolve) => {
      timerId = window.setTimeout(async () => {
        const result = await func(...args);
        timerId = null;
        resolve(result);
      }, delay);
    });
  };
};

export const validators = {
  required: (message: string = "Field is required") => {
    return (ctx: TContext<any, any, TConfig<any, any>>) => {
      if (!ctx.value) {
        // ❌ Error
        return message;
      }

      // ✅ Success
      return "";
    };
  },
  regexp: (regexp: RegExp, message: string = "Invalid format") => {
    return (ctx: TContext<any, any, TConfig<any, any>>) => {
      const isValid = regexp.test(ctx.value);

      if (!isValid) {
        // ❌ Error
        return message;
      }

      // ✅ Success
      return "";
    };
  },
  optionalRegexp: (regexp: RegExp, message: string = "Invalid format") => {
    return (ctx: TContext<any, any, TConfig<any, any>>) => {
      if (!ctx.value) {
        return "";
      }

      const isValid = regexp.test(ctx.value);

      if (!isValid) {
        // ❌ Error
        return message;
      }

      // ✅ Success
      return "";
    };
  },
  max: (
    max: number,
    message: string = `The maximum string length must not exceed ${max} characters`
  ) => {
    return (ctx: TContext<any, any, TConfig<any, any>>) => {
      const isValid = (ctx.value?.length || 0) <= max;

      if (!isValid) {
        // ❌ Error
        return message;
      }

      // ✅ Success
      return "";
    };
  },
  min: (
    min: number,
    message: string = `The minimum string length is ${min} characters`
  ) => {
    return (ctx: TContext<any, any, TConfig<any, any>>) => {
      const isValid = (ctx.value?.length || 0) >= min;

      if (!isValid) {
        // ❌ Error
        return message;
      }

      // ✅ Success
      return "";
    };
  },
  optionalMin: (
    min: number,
    message: string = `The minimum string length is ${min} characters`
  ) => {
    return (ctx: TContext<any, any, TConfig<any, any>>) => {
      if (!ctx.value) {
        return "";
      }

      const isValid = (ctx.value?.length || 0) >= min;

      if (!isValid) {
        // ❌ Error
        return message;
      }

      // ✅ Success
      return "";
    };
  },
};
