import { noop } from "@greatness/util";
import { yupResolver } from "@hookform/resolvers/yup";
import { useMemo } from "react";
import type {
  DefaultValues,
  FieldValues,
  RegisterOptions,
  UseFormReset,
} from "react-hook-form";
import { FormProvider, useForm } from "react-hook-form";

/* eslint-disable @typescript-eslint/no-explicit-any */
export type ResetForm<T extends FieldValues = any> = UseFormReset<T>;
export type FormValidation = any;
/* eslint-enable @typescript-eslint/no-explicit-any */
type HandleSubmit<T extends FieldValues> = (values: T) => Promise<void>;

type FormDefaultValues = Record<
  string,
  unknown[] | boolean | number | string | undefined
>;
export interface IFormProperties<T extends FieldValues = FormDefaultValues> {
  autocomplete?: string;
  children: React.ReactNode;
  className?: string;
  defaultValues?: DefaultValues<T>;
  handleSubmit?: HandleSubmit<T>;
  isDisabled?: boolean;
  validation?: FormValidation;
}
export interface IFormError {
  message: string;
  type: keyof RegisterOptions | "email" | "manual";
}

const Form = <T extends FieldValues>(
  props: IFormProperties<T>,
): React.ReactElement => {
  const {
    children,
    handleSubmit: handleSubmitProp = noop,
    validation,
    className,
    defaultValues,
    autocomplete,
  } = props;
  const methods = useForm<T>({
    defaultValues,
    mode: "onBlur",
    ...(validation && {
      resolver: yupResolver(validation),
    }),
  });

  const { handleSubmit } = methods;

  const onSubmit = useMemo(
    () => handleSubmit(async (values) => handleSubmitProp(values)),
    [handleSubmit, handleSubmitProp],
  );

  return (
    <FormProvider {...methods}>
      <form
        className={className}
        onSubmit={onSubmit}
        noValidate
        autoComplete={autocomplete}
      >
        {children}
      </form>
    </FormProvider>
  );
};

export default Form;
