import React, { useCallback, useMemo } from 'react';
import { uniqueId } from 'lodash';
import { Select } from './select';
import { MaskedInput } from './masked-input';
import { Input as DefaultInput } from './input';
import { RadioGroup } from './radio-group/radio-group';
import { InputNumber } from './input-number';
import { SField } from './s-field';
import { Cell } from './cell/cell';
import { Multiselect } from './multiselect/multiselect';
import { PHONE_FORMAT, Widget } from '../../constants';
import { ExpandableNotes } from './notes/expandable-notes';
import { LinksInput } from './links';
import { FlatInput } from './flat-input';
import { RangeSlider } from './range-slider';
import { GroupSelect } from './group-select';
import { DatePicker, DatePickerMode, PopupAlignment } from 'common/components/form/date-picker';
import { AutocompleteInput } from '../autocomplete-input/autocomplete-input';
import { LinkfireSearch } from '../linkfire-search/linkfire-search';
import { Tooltip } from '../tooltip';
import { useField } from 'formik';
import { BadgeSelector } from 'common/components/form/badge-selector';
import { LimitedLengthTextField } from 'common/components/form/limited-length-text-field';
import { CreatableSelect } from 'common/components/form/creatable-select';
import { ActionButtonSelect } from 'common/components/form/action-button-select';

const renderField = (type, props, id) => {
  switch (type) {
    case Widget.Select:
      return <Select {...props} id={id} />;
    case Widget.MultiSelect:
      return <Multiselect {...props} id={id} />;
    case Widget.GroupSelect:
      return <GroupSelect {...props} id={id} />;
    case Widget.Date:
      return <DatePicker mode={DatePickerMode.SINGLE} alignment={PopupAlignment.Left} {...props} id={id} />;
    case Widget.Toggle:
    case Widget.RadioGroup:
      return <RadioGroup {...props} id={id} />;
    case Widget.Currency:
      return <InputNumber {...props} id={id} type={type} />;
    case Widget.PhoneNumber:
      return <MaskedInput mask={PHONE_FORMAT} {...props} type={type} id={id} />;
    case Widget.Notes:
      return <ExpandableNotes {...props} id={id} />;
    case Widget.Links:
      return <LinksInput {...props} id={id} />;
    case Widget.FlatInput:
      return <FlatInput {...props} id={id} />;
    case Widget.RangePicker:
      return <RangeSlider {...props} id={id} />;
    case Widget.Autocomplete:
      return <AutocompleteInput {...props} id={id} />;
    case Widget.LinkfireSearch:
      return <LinkfireSearch {...props} id={id} />;
    case Widget.BadgeSelector:
      return <BadgeSelector {...props} id={id} />;
    case Widget.LimitedTextField:
      return <LimitedLengthTextField {...props} id={id} />;
    case Widget.CreatableSelect:
      return <CreatableSelect {...props} id={id} />;
    case Widget.ActionableSelect:
      return <ActionButtonSelect {...props} id={id} />;
    default:
      return <DefaultInput type={type} {...props} id={id} />;
  }
};

export const Field = props => {
  const {
    warning,
    type,
    className,
    wide,
    direction,
    noPaddings,
    dataSelector,
    shouldShowTooltip,
    tooltipContent,
    labelTooltipContent,
    shouldShowFieldTooltip = false,
    fieldTooltipContent,
    fieldClassName,
    format,
    onError,
    onPostChange,
    ...restProps
  } = props;
  const defaultMapper = value => value;
  const [field, meta, helpers] = useField({
    name: restProps.name,
    validate: restProps.validate,
    parse: restProps.normalize || defaultMapper,
    format: format || defaultMapper,
  });
  const { touched, error } = meta;
  const id = uniqueId();

  const showError = meta.error && touched;
  const showWarning = warning && touched;

  const handleError = useCallback(
    (error: string) => {
      helpers.setError(error);
      onError?.(error);
    },
    [helpers, onError]
  );

  const handleChange = useCallback(
    value => {
      field.onChange(value);
      onPostChange?.(value);
    },
    [onPostChange, field]
  );

  const inputProps = useMemo(
    () => ({
      ...restProps,
      value: field.value,
      onChange: handleChange,
      onError: handleError,
      onBlur: () => helpers.setTouched(true),
      onResetError: () => {
        helpers.setError(undefined);
        restProps?.resetError?.();
      },
      dataSelector,
      isInvalid: showError,
      className: fieldClassName,
    }),
    [dataSelector, handleChange, field.value, fieldClassName, handleError, helpers, restProps, showError]
  );
  const { label } = inputProps;

  const element = useMemo(() => renderField(type, inputProps, id), [id, inputProps, type]);
  return (
    <SField className={className}>
      <Cell
        dataSelector={dataSelector}
        wide={wide}
        editable
        label={label}
        direction={direction}
        shouldShowTooltip={shouldShowTooltip}
        tooltipContent={tooltipContent}
        error={showError || showWarning ? error || warning : false}
        noPaddings={noPaddings}
        labelTooltipContent={labelTooltipContent}
      >
        <Tooltip enabled={shouldShowFieldTooltip} content={fieldTooltipContent}>
          <div>{element}</div>
        </Tooltip>
      </Cell>
    </SField>
  );
};
