import { ElementType, useRef } from 'react';
import * as uuid from 'uuid';
import { CustomFieldInputProps } from './CustomFieldInputProps';
import { CustomFieldMetaProps } from './CustomFieldMetaProps';
import { RenderComponent, RenderComponentProps } from './Field';
import { InjectedFieldProps } from './InjectedFieldProps';

export type StandAloneInputProps<
  TValue,
  TRenderComponent extends ElementType
> = {
  /** Component to render inside of the field. */
  Component: RenderComponent<TValue, TRenderComponent>;
  /** Value of the field. */
  value: TValue;
  /** Function to change the value of the field. */
  onChange: (arg: TValue) => void;
} & Omit<
  RenderComponentProps<TValue, TRenderComponent>,
  | keyof InjectedFieldProps<TValue>
  | 'value'
  | 'onChange'
  | 'normalize'
  | 'validate'
>;

/** The stand alone version of `<Field/>`. Can use a type of input component outside of a `<Form/>`. */
export default function StandAloneInput<TValue, TComponent extends ElementType>(
  props: StandAloneInputProps<TValue, TComponent>
) {
  const { Component, value, onChange, disabled, ...rest } = props;
  const handleChange = (arg: TValue) => {
    if (!disabled) {
      onChange(arg);
    }
  };
  const Wrapped = Component as React.ComponentType<InjectedFieldProps<TValue>>;
  const idRef = useRef(uuid.v4());
  const input: CustomFieldInputProps<TValue> = {
    id: idRef.current,
    name: idRef.current,
    value: value,
    onChange: handleChange,
    onBlur: () => {},
  };

  const meta: CustomFieldMetaProps<TValue> = {
    warning: undefined,
    value: value,
    touched: false,
    initialTouched: false,
  };

  return <Wrapped {...rest} disabled={disabled} input={input} meta={meta} />;
}
