import { type RegisterOptions, type Validate } from 'react-hook-form';

import {
  validateDateRequiredRule,
  validateDecimalRule,
  validateIsAfterDate,
  validateIsBeforeDate,
  validateIsSameDate,
  validateMaxStringRule,
  validateMinStringRule,
  validateRequiredStringRule,
  validateRequiredStringWithMessageRule,
  validateTimeRequiredRule,
} from 'src/utils/validation';

type ValidateFunction = (ruleValue?: any) => (value?: any) => Promise<any>;

type DateRuleOptions = {
  date: Date;
  message: string;
};

const ruleToValidation: Record<string, ValidateFunction> = {
  afterDate: ({ date, message }: DateRuleOptions) =>
    validateIsAfterDate(date, message),
  beforeDate: ({ date, message }: DateRuleOptions) =>
    validateIsBeforeDate(date, message),
  sameDate: ({ date, message }: DateRuleOptions) =>
    validateIsSameDate(date, message),
  requiredDate: () => validateDateRequiredRule,
  requiredTime: () => validateTimeRequiredRule(),
  requiredString: () => validateRequiredStringRule,
  requiredStringWithMessage: (message?: string) =>
    validateRequiredStringWithMessageRule(message),
  maxString: validateMaxStringRule,
  minString: validateMinStringRule,
  decimal: validateDecimalRule,
};

export type RulesOptions = Partial<{
  afterDate: DateRuleOptions;
  beforeDate: DateRuleOptions;
  sameDate: DateRuleOptions;
  requiredDate: boolean;
  requiredTime: boolean;
  requiredString: boolean;
  requiredStringWithMessage: string;
  maxString: number;
  minString: number;
  decimal: boolean;
}>;

export type Rules = Omit<RegisterOptions, 'validate'> &
  Partial<{ validate: Record<string, Validate<any, any>> }>;

export const useRules = (options: RulesOptions, customValidations?: any) => {
  let rules: Rules = {};

  Object.entries(options).forEach(([option, value]) => {
    if (!value) return;

    const validate = ruleToValidation[option];
    if (!validate) return;

    const validation = validate(value);
    const type = 'validate';

    const oldRules = rules[type] || {};
    const newRules = { [option]: validation };

    rules = {
      ...rules,
      [type]: {
        ...oldRules,
        ...newRules,
      },
    };
  });

  return {
    ...rules,
    validate: {
      ...customValidations,
      ...rules.validate,
    },
  };
};

export default useRules;
