/* eslint react/prop-types: 0 */
import classNames from 'classnames';
import extend from 'extend';
import React from 'react';
import * as constants from '../../constants';

import {
  compose,
  mapProps,
  withState,
  withHandlers,
  setPropTypes,
  setDisplayName,
} from 'recompose';

import KdChickletsContainer from '../KdChickletsContainer';
import KdChickletsContainerDraggable from '../KdChickletsContainerDraggable';

import { dProps, pTypes } from './propTypes';
import { addItemHandler, behaviorHandler, errorHandler, optionHandler } from './handlers';
import { addChicklet, setChicklets, removeItem } from './chickletsHandler';
import { transformKdModel, transformMultipleKdModel } from '../../utils';

import karmadataTheme from '../../themes/karmadata.scss';

const ItemContainerWrapper = WrappedComponent => (props) => {
  const {
    setErrors,
    setItems,
    clearErrors,
    wrapperState: { itemsState },
    setOption,
    theme,
    isChickletNone,
    chicklets,
    chicklets: { sortable },
  } = props;

  const clearChicklets = (fireEvents = false) => {
    const { chicklets: { clearAll }, events, kdFilterModel } = props;
    let callback;
    if (fireEvents) {
      const data =
        kdFilterModel && kdFilterModel.getFilterItemValue
          ? { model: kdFilterModel, ...kdFilterModel.getFilterItemValue() }
          : 'Clear Values';

      callback = () => events && events.onChange && events.onChange({ data });
    }

    props.resetItems(callback);

    if (fireEvents && clearAll && clearAll.onClick) {
      clearAll.onClick();
    }
  };

  const addError = ({ errors }) => {
    setErrors(errors);
    if (isChickletNone()) {
      clearChicklets();
    }
  };

  const containerVisible = () => {
    const { chicklets: { container: { visible } } } = props;
    return visible;
  };

  const updateItemPosition = (value, position) => {
    const { kdFilterModel, events } = props;
    const itemIndex = itemsState.findIndex(elem => elem.value === value);
    const item = itemsState.splice(itemIndex, 1);

    const callback = () =>
      events &&
      events.onChange &&
      events.onChange({
        data: {
          model: kdFilterModel,
          values: { ...kdFilterModel.getSortOrderModelValue() },
        },
      });
    itemsState.splice(position, 0, item[0]);
    setItems({ items: itemsState, model: kdFilterModel, callback });
  };

  const toggleItemDirection = (value) => {
    const { kdFilterModel, events } = props;
    const items = itemsState.map((item, index) => {
      if (item.value === value) {
        const direction = item.direction === constants.ASC ? constants.DESC : constants.ASC;
        const selectedItems = kdFilterModel.getSortOrderModelValue();
        selectedItems[index].direction = direction;
        kdFilterModel.setSelected(
          selectedItems.map(selectedItem => ({
            propertyName: selectedItem.propertyName,
            direction: selectedItem.direction,
          }))
        );

        events &&
          events.onChange &&
          events.onChange({
            data: {
              model: kdFilterModel,
              values: { ...kdFilterModel.getSortOrderModelValue() },
            },
          });
        return Object.assign({}, item, { direction });
      }
      return item;
    });

    setItems({ items, model: kdFilterModel });
  };

  const changeOption = o => setOption(o);

  const lastInitialValue = () => (itemsState.length ? itemsState : props.selectedValuesInitial || [])[0];

  const hasInitialValues = () => !!(props.selectedValuesInitial && props.selectedValuesInitial.length);
  return (
    <div className={classNames('c-kd', theme['c-kd'])}>
      <WrappedComponent
        {...props}
        onItemAdded={props.addChicklet}
        onItemRemoved={props.removeItem}
        onOptionSelected={changeOption}
        onError={addError}
        clearErrors={clearErrors}
        valuesLimit={isChickletNone() ? 1 : props.valuesLimit}
        isChickletNone={isChickletNone()}
        onClearChicklets={clearChicklets}
        onSetChicklets={props.setChicklets}
        emptyItems={!itemsState.length}
        lastInitialValue={lastInitialValue}
        hasInitialValues={hasInitialValues}
      />

      {!sortable &&
        containerVisible() && (
          <KdChickletsContainer
            theme={theme}
            items={itemsState}
            showAtBeginning={props.chicklets.insertAtBeginning}
            isChickletNone={isChickletNone()}
            labelHandler={props.chicklets.labelHandler}
          />
        )}

      {sortable &&
        containerVisible() && (
          <KdChickletsContainerDraggable
            theme={theme}
            updateItemPosition={updateItemPosition}
            toggleItemDirection={toggleItemDirection}
            chicklets={{ ...chicklets, sortable: true, fullwidth: true }}
            items={itemsState}
            labelHandler={props.chicklets.labelHandler}
          />
        )}
    </div>
  );
};

const defaultPropMerge = (props) => {
  if (props.theme !== undefined) {
    return extend(true, {}, dProps, props);
  }

  return extend(true, {}, dProps, props, { theme: karmadataTheme });
};

const state = compose(
  setDisplayName('WrapperComponent'),
  setPropTypes(pTypes),
  withState('wrapperState', 'setWrapperState', {
    itemsState: [],
    errorState: null,
    optionState: null,
  })
);

const props = compose(
  mapProps(props => ({
    ...props,
    ...defaultPropMerge(props),
    ...transformKdModel(props),
  }))
);

const propsMultiple = compose(
  mapProps(props => ({
    ...props,
    ...defaultPropMerge(props),
    ...transformMultipleKdModel(props),
  }))
);

const propsSortable = compose(
  mapProps(props => ({
    ...props,
    ...defaultPropMerge({
      ...props,
      chicklets: {
        ...props.chicklets,
        sortable: true,
      },
    }),
    ...transformKdModel(props),
  }))
);

const enhancer = compose(
  withHandlers({
    ...addItemHandler,
    ...behaviorHandler,
    ...errorHandler,
    ...optionHandler,
  }),
  withHandlers({ removeItem }),
  withHandlers({ addChicklet, setChicklets }),
  ItemContainerWrapper
);

export default compose(state, props, enhancer);

export const enhancerMultiple = compose(state, propsMultiple, enhancer);
export const enhancerSortable = compose(state, propsSortable, enhancer);
