/* eslint-disable react/display-name */
import React, { ChangeEvent } from "react";
import { DatePicker, Form, Input, InputNumber, Select } from "antd";
import { Text } from "@/components/Typography/Text";

const FormItem = Form.Item;
const { Option } = Select;

import { FormItemProps as $FormItemProps } from "antd/lib/form/FormItem";
import { InputProps as $ItemProps } from "antd/lib/input";
import { SelectProps as $SelectProps } from "antd/lib/select";
import { FieldConfig, FieldProps, getIn } from "formik";
import classNames from "classnames";

type SelectOption = {
    label: string;
    value: string | number;
};
  
export enum FieldType {
  input = "input",
  inputNumber = "input-number",
  textarea = "textarea",
  select = "select",
  time = "time",
  date = "date",
}

export type FormItemProps = {
  children: React.ReactNode;
} & {
  label: string;
  name: string;
  isInt?: boolean;
  description: string;
  className?: string;
  labelClassName?: string;
  descriptionClassName?: string;
  inputClassName?: string;
  formItemClassName?: string;
  submitCount: number;
  onChangeText?: (text: string) => void;
  type: FieldType;
  beforeSetValue?: <T>(value: T) => T;
} & $FormItemProps &
  $ItemProps &
  $SelectProps<any> &
  FieldProps &
  Pick<FieldConfig, "validate">;

const CreateAntField =
  (AntComponent: any) =>
  ({
    description,
    field,
    form,
    label,
    className,
    labelClassName,
    descriptionClassName,
    inputClassName,
    formItemClassName,
    selectOptions,
    submitCount,
    type,
    beforeSetValue,
    isInt,
    onChangeText,
    ...props
  }: any) => {
    const touched = getIn(form.touched, field.name);
    const submitted = submitCount > 0;
    const hasError = getIn(form.errors, field.name);
    const submittedError = hasError && submitted;
    const touchedError = hasError && touched;

    const onBlur = () => form.setFieldTouched(field.name, true);

    const onInputChange = (event: ChangeEvent<HTMLInputElement>) => {
      event &&
        event.target &&
        form.setFieldValue(
          field.name,
          typeof beforeSetValue === "function"
            ? beforeSetValue(event.target.value)
            : event.target.value
        );
      onChangeText?.(event?.target?.value || "");
    };
    const onChange = (value: any) => {
      try {
        let text = value;

        if (isInt) {
          if (!value) {
            text = 1;
          } else {
            const number = parseInt(value);
            text = number === NaN ? 1 : number;
          }
        }

        form.setFieldValue(
          field.name,
          typeof beforeSetValue === "function" ? beforeSetValue(value) : text
        );
        onChangeText(text);
      } catch (error) {}
    };

    const onTimeChange = (value: any) => {
      onBlur();
      form.setFieldValue(
        field.name,
        typeof beforeSetValue === "function" ? beforeSetValue(value) : value
      );
    };

    return (
      <div className={className}>
        {label && (
          <Text
            className={classNames(
              "d--block leading-22",
              !description && "m__b--4",
              typeof label === "string" && "text--tundola",
              labelClassName
            )}
          >
            {label}
          </Text>
        )}
        {description && (
          <Text
            className={classNames("d--block m__b--8", descriptionClassName)}
          >
            {description}
          </Text>
        )}
        <FormItem
          className={formItemClassName}
          help={submittedError || touchedError ? hasError : false}
          validateStatus={submittedError || touchedError ? "error" : "success"}
        >
          <AntComponent
            {...field}
            {...props}
            className={inputClassName}
            onBlur={[FieldType.time].includes(type) ? onTimeChange : onBlur}
            onChange={
              [
                FieldType.input,
                FieldType.textarea,
                FieldType.inputNumber,
              ].includes(type)
                ? onInputChange
                : onChange
            }
          >
            {selectOptions &&
              selectOptions.map((option: SelectOption, index: number) => (
                <Option key={index} value={option.value}>
                  {option.label}
                </Option>
              ))}
          </AntComponent>
        </FormItem>
      </div>
    );
  };
export const AntSelect = CreateAntField(Select);
export const AntInput = CreateAntField(Input);
export const AntInputNumber = CreateAntField(InputNumber);
export const AntTextArea = CreateAntField(Input.TextArea);
export const AntDatePicker = CreateAntField(DatePicker);
//export const AntTimePicker = CreateAntField(TimePickerDesktop);
