import React, { PropTypes } from 'react';
import extend from 'extend';

import KdSelectItemContainer from '../KdSelectItemContainer';
import KdSelectItemContainerDraggable from '../KdSelectItemContainerDraggable';
import * as constants from '../../constants';

export default function wrap(WrappedComponent, draggable = false) {
  const defaultProps = {
    selectBehavior: constants.ADD_CHICKLET,
    isDisabled: false,
    mainSelector: {
      visible: false,
      selected: '',
      optionValues: {
        anyOption: {
          visible: true,
        },
        customOptions: [],
        userSpecifiedOption: {
          visible: true,
        },
      },
    },
    chicklets: {
      sortable: false,
      visible: true,
      fullwidth: false,
      buttons: {
        ascDesc: { visible: false },
        info: { visible: false },
      },
      events: {},
      clearAll: { visible: false },
    },
  };

  const propTypes = {
    selectBehavior: PropTypes.string,

    events: PropTypes.shape({
      onSelect: PropTypes.func,
      onChange: PropTypes.func,
    }),

    api: PropTypes.shape({
      url: PropTypes.string.isRequired,
      key: PropTypes.string.isRequired,
    }),

    mainSelector: PropTypes.shape({
      visible: PropTypes.bool,
      selected: PropTypes.string,

      optionValues: PropTypes.shape({
        selectOption: PropTypes.shape({
          visible: PropTypes.bool,
          label: PropTypes.string,
        }),
        anyOption: PropTypes.shape({
          visible: PropTypes.bool,
          label: PropTypes.string,
        }),
        customOptions: PropTypes.array,
        userSpecifiedOption: PropTypes.shape({
          visible: PropTypes.bool,
          label: PropTypes.string,
        }),
      }),
    }),

    chicklets: PropTypes.shape({
      sortable: PropTypes.bool,
      visible: PropTypes.bool,
      fullwidth: PropTypes.bool,
      prefix: PropTypes.string,

      buttons: PropTypes.shape({
        ascDesc: PropTypes.shape({ visible: PropTypes.bool }),
        info: PropTypes.shape({ visible: PropTypes.bool }),
      }),

      events: PropTypes.shape({
        onClick: PropTypes.func,
        onClose: PropTypes.func,
      }),

      clearAll: PropTypes.shape({
        visible: PropTypes.bool,
        onClick: PropTypes.func,
      }),
    }),
  };

  class ItemContainerWrapper extends React.Component {
    constructor(props) {
      super(props);

      this.mainSelector = extend(true, {}, defaultProps.mainSelector, this.props.mainSelector);
      this.chicklets = extend(true, {}, defaultProps.chicklets, this.props.chicklets);

      this.state = { items: [], option: null, item: null };

      this.addItem = this.addItem.bind(this);
      this.removeItem = this.removeItem.bind(this);
      this.changeOption = this.changeOption.bind(this);
      this.clearChicklets = this.clearChicklets.bind(this);
      this.setChicklets = this.setChicklets.bind(this);
      this.updateItemPosition = this.updateItemPosition.bind(this);
      this.toggleItemDirection = this.toggleItemDirection.bind(this);
    }

    addItem({ value, chickletLabel, option, inputVisible, remove, category, direction }) {
      let { items } = this.state;

      if (!value || !chickletLabel) {
        return this.removeItem(option);
      }

      const newItem = {
        value,
        option,
        direction,
        label: chickletLabel,
        key: option,
        category,
        onRemove: () => {
          this.removeItem(option);
          remove && remove();
        },
      };

      if (this.isChickletNone()) {
        newItem.autocompleteVisible = inputVisible;
        newItem.isChickletNone = this.isChickletNone();
        newItem.hasMainSelector = true;

        items = [newItem];
      } if (this.isAddChickletSingle()) {
        items = [newItem];
      } else {
        const index = items.findIndex(item => item.key === option);
        (index > -1) ? items.splice(index, 1, newItem) : items.push(newItem);
      }

      this.setState({ items, item: newItem, option });
    }

    removeItem(option) {
      const { items } = this.state;
      const index = items.findIndex(item => item.key === option);
      if (index > -1) {
        items.splice(index, 1);
      }

      this.setState({ items, item: null });
    }

    changeOption(option) {
      this.setState({ option });
    }

    clearChicklets() {
      this.setState(Object.assign({}, this.state, { items: [], item: null }));
    }

    setChicklets(chicklets) {
      const items = chicklets.map(({ value, chickletLabel, option, direction }) => (
        {
          value,
          option,
          direction,
          label: chickletLabel,
          key: option,
          onRemove: () => this.removeItem(option),
        }),
      );

      const item = [...items].pop();
      this.setState(Object.assign({}, this.state, { items, item }));
    }

    updateItemPosition(value, position) {
      const { items } = this.state;
      const itemIndex = items.findIndex(elem => (elem.value === value));
      const item = items.splice(itemIndex, 1);

      items.splice(position, 0, item[0]);
      this.setState(Object.assign({}, this.state, items));
    }

    toggleItemDirection(value) {
      const items = this.state.items.map((item) => {
        if (item.value === value) {
          const direction = item.direction === constants.ASC ? constants.DESC : constants.ASC;
          return Object.assign({}, item, { direction });
        }

        return item;
      });

      this.setState(Object.assign({}, this.state, { items }));
    }

    isChickletNone() {
      return (constants.CHICKLET_NONE === this.props.selectBehavior);
    }

    isAddChickletSingle() {
      return (constants.ADD_CHICKLET_SINGLE === this.props.selectBehavior);
    }

    isAddChicklet() {
      return (constants.ADD_CHICKLET === this.props.selectBehavior);
    }

    render() {
      return (
        <div>
          <WrappedComponent
            {...this.props}
            onItemAdded={this.addItem}
            onItemRemoved={this.removeItem}
            onOptionSelected={this.changeOption}
            isChickletNone={this.isChickletNone()}
            onClearChicklets={this.clearChicklets}
            onSetChicklets={this.setChicklets}
            emptyItems={!this.state.items.length}
          />

          {
            !draggable &&
              <KdSelectItemContainer
                items={this.state.items}
                chicklets={this.chicklets}
              />
          }

          {
            !this.isChickletNone() &&
              draggable &&
              <KdSelectItemContainerDraggable
                updateItemPosition={this.updateItemPosition}
                items={this.state.items}
                toggleItemDirection={this.toggleItemDirection}
                chicklets={this.chicklets}
              />
          }
        </div>
      );
    }
  }

  ItemContainerWrapper.defaultProps = defaultProps;
  ItemContainerWrapper.propTypes = propTypes;

  return ItemContainerWrapper;
}
