import { Field, FieldProps, FieldAttributes, FormikProps } from "formik";
import React, { LabelHTMLAttributes } from "react";
import styles from "./Input.module.css";
import classnames from "classnames";

type CustomInputProps<T> = {
  customRender?: (fieldProps: FieldProps) => React.ReactNode;

  customOnChange?: (
    event: React.ChangeEvent<HTMLInputElement>,
    form: FormikProps<T>
  ) => void;
};

export function Label({
  children,
  ...props
}: LabelHTMLAttributes<HTMLLabelElement>) {
  return (
    <label className={classnames(styles.label, props.className)} {...props}>
      {children}
    </label>
  );
}

export function Hint({
  children,
  ...props
}: LabelHTMLAttributes<HTMLLabelElement>) {
  return (
    <label className={classnames(styles.hint, props.className)} {...props}>
      {children}
    </label>
  );
}

export default function Input<T>(
  props: CustomInputProps<T> &
    FieldAttributes<{ hint?: string; label?: string; disabled?: boolean }>
) {
  const generatedId = React.useId();

  return (
    <div className={classnames("form-row", styles.formRow)}>
      {props.label ? <Label htmlFor={generatedId}>{props.label}</Label> : null}
      <Field id={generatedId} {...props}>
        {(fieldProps: FieldProps) => {
          let { field, meta, form } = fieldProps;
          let textAfterField =
            meta.touched && meta.error ? (
              <p className={styles.error}>{meta.error}</p>
            ) : (
              props.hint && <p className={styles.hint}>{props.hint}</p>
            );

          // <input type="file"> in React is always uncontrolled, so we have to hardcode
          // the value to "" if it's a file picker
          const inputFields =
            props.type === "file"
              ? (() => {
                  let clonedField = Object.assign({}, field);
                  delete clonedField.value;
                  return clonedField;
                })()
              : field;

          return (
            <>
              {props.customRender == null ? (
                <input
                  type={props.type}
                  placeholder={props.placeholder}
                  disabled={props.disabled}
                  title={props.title}
                  {...inputFields}
                  onChange={(event) => {
                    console.log(event);
                    if (props.customOnChange) {
                      console.log("using custom on change");
                      props.customOnChange(event, form);
                    } else {
                      form.setFieldValue(field.name, event.currentTarget.value);
                    }
                  }}
                />
              ) : (
                props.customRender(fieldProps)
              )}
              {textAfterField}
            </>
          );
        }}
      </Field>
    </div>
  );
}
