import React, { PropTypes } from 'react';
import unionby from 'lodash.unionby';
import classNames from 'classnames';
import extend from 'extend';
import { dispatchCustomEvent, removeLabel } from '../../utils';
import { KdSelect } from '../KdSelect';
import KdAutocomplete from '../KdAutocomplete';
import KdSelectItemContainer from '../KdSelectItemContainer';
import KdSelectItemContainerDraggable from '../KdSelectItemContainerDraggable';

import { ASC, DESC, ADD_CHICKLET, ADD_CHICKLET_SINGLE, CHICKLET_NONE } from '../../constants';
const defaultProps = {
  selectedValuesInitial: [],
  selectBehavior: ADD_CHICKLET,
  isDisabled: false,
  mainSelector: {
    visible: false,
    selected: '',
    optionValues: {
      anyOption: {
        visible: true,
      },
      selectOption: {
        visible: true,
      },
      customOptions: [],
      userSpecifiedOption: {
        visible: true,
      },
    }
  },
  chicklets: {
    sortable: false,
    visible: true,
    fullwidth: false,
    buttons: {
      ascDesc: { visible: false },
      info: { visible: false },
    },
    events: {},
    clearAll: { visible: false },
  },
  events: {},
  autoComplete: {
    clearTextboxOnSelection: true,
    renderClearTextboxButton: true,
  }
};

const propTypes = {
  selectBehavior: PropTypes.string,
  kdFilterModel: PropTypes.object.isRequired,

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

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

  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,
      }),
    })
  }),

  autoComplete: PropTypes.shape({
    onSuccess: PropTypes.func,
    onRender: PropTypes.func,
    onSelect: PropTypes.func,
    onFail: PropTypes.func,
    onDone: PropTypes.func,
    placeholderText: PropTypes.string,
    clearTextboxOnSelection: PropTypes.bool,
    renderClearTextboxButton: PropTypes.bool,
  }),

  // Chicklets Props (before rename)
  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,
    }),
  }),
  selectedValuesInitial: PropTypes.array,
};

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

    this.isChickletSingle = this.isChickletSingle.bind(this);
    this.isChickletNone = this.isChickletNone.bind(this);
    this.isSelectOne = this.isSelectOne.bind(this);
    this.lastInitialValue = this.lastInitialValue.bind(this);
    this.hasInitialValues = this.hasInitialValues.bind(this);
    this.displayAutocomplete = this.displayAutocomplete.bind(this);
    this.setAutocompleteVisibility = this.setAutocompleteVisibility.bind(this);
    this.setLoading = this.setLoading.bind(this);
    this.resetSelected = this.resetSelected.bind(this);
    this.setSelectedItems = this.setSelectedItems.bind(this);
    this.handleRemove = this.handleRemove.bind(this);
    this.clearAll = this.clearAll.bind(this);
    this.renderSelectedItems = this.renderSelectedItems.bind(this);
    this.renderClearAll = this.renderClearAll.bind(this);
    this.renderKdSelectEntity = this.renderKdSelectEntity.bind(this);
    this.renderKdSelect = this.renderKdSelect.bind(this);
    this.renderKdAutocomplete = this.renderKdAutocomplete.bind(this);
    this.updateItemPosition = this.updateItemPosition.bind(this);
    this.toggleItemDirection = this.toggleItemDirection.bind(this);

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

    let selectedItems = this.props.selectedValuesInitial || [];
    if (this.isSelectOne()) {
      const value = this.lastInitialValue();
      if (value) {
        selectedItems = [value];
      }
    }

    // NOTE: we need this for changes on the fly with Plain JS.
    selectedItems = selectedItems.map((item, i) => ({...item, direction: ASC }) );
    this.state = {
      selectedItems: selectedItems,
      autocompleteVisible: this.displayAutocomplete(),
      isLoading: false
    };
  }

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

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

  isSelectOne() {
    return (this.isChickletNone() || this.isChickletSingle());
  }

  lastInitialValue() {
    return this.props.selectedValuesInitial.slice(-1)[0];
  }

  hasInitialValues() {
    return !!(this.props.selectedValuesInitial.length);
  }

  displayAutocomplete() {
    const { mainSelector } = this;
    let res = !mainSelector.visible;
    if (mainSelector.optionValues.userSpecifiedOption.visible !== false) {
      res = res || this.hasInitialValues();
    }
    return res;
  }

  setAutocompleteVisibility(value) {
    this.setState({ autocompleteVisible: !!value });
  }

  setLoading(value) {
    this.setState({ isLoading: !!value })
  }

  resetSelected() {
    this.setState({ selectedItems: [] });
  }

  setSelectedItems(item) {
    const { events } = this.props;
    const direction = ASC;
    let selectedItems;
    if (this.isSelectOne()) {
      selectedItems = [{ ...item, direction }];
      if (this.isChickletNone() && this.kdAutocomplete != null) {
        this.kdAutocomplete.setInputValue(item.label);
      }
    } else {
      selectedItems = unionby(this.state.selectedItems, [{ ...item, direction }], 'value');
    }
    this.setState({ selectedItems });
    dispatchCustomEvent(this.rootElement, 'kd:ui:SelectEntity:onSelect', { data: item });
    events.onChange && events.onChange({ data: { ...item, direction } });
    events.onSelect && events.onSelect({ data: { ...item, direction } });
  }

  toggleItemDirection(value){
    const { selectedItems } = this.state;
    let item = selectedItems.find((elem) => (elem.value === value));
    const direction = item.direction;
    item.direction = (direction === ASC || direction === undefined ) ? DESC : ASC;
    this.setState({ selectedItems });
  }

  updateItemPosition(value, position) {
    const { selectedItems } = this.state;
    let itemIndex = selectedItems.findIndex((elem) => (elem.value === value));
    const item = selectedItems.splice(itemIndex, 1);
    selectedItems.splice(position, 0, item[0]);
    this.setState({ selectedItems });
  }

  handleRemove(elem) {
    const selectedItems = removeLabel(this.state.selectedItems, elem.label);
    this.setState({ selectedItems });
    dispatchCustomEvent(this.rootElement, 'kd:ui:SelectEntity:onClose', { elem } );
    if (this.isChickletNone()) {
      if (this.kdAutocomplete != null) {
        this.kdAutocomplete.setInputValue();
      }
    }
    this.props.events.onChange && this.props.events.onChange({ data: { elem } });
  }

  renderSelectedItems() {
    const {
      chicklets,
      kdFilterModel,
      api,
      autoComplete,
    } = this.props;
    const selectedItems = this.state.selectedItems.map(
      (item) => {
        return {
          key: item.value,
          label: item.label,
          value: item.value,
          direction: item.direction,
          isChickletNone: this.isChickletNone(),
          onRemove: this.handleRemove,
          isLoading: this.state.isLoading,
          autocompleteVisible: this.state.autocompleteVisible,
          hasMainSelector: this.mainSelector.visible,
          toggleItemDirection: this.toggleItemDirection,
          item: item,
          chicklets,
          kdFilterModel,
          api,
          autoComplete,
        };
      }
    );
    if (selectedItems.length) {
      if (chicklets.sortable) {
        return (
          <KdSelectItemContainerDraggable
            items={selectedItems}
            updateItemPosition={this.updateItemPosition}
          />
        );
      } else {
        return <KdSelectItemContainer items={selectedItems} />;
      }
    }
  }

  clearAll() {
    this.setState({
      selectedItems: [],
      autocompleteVisible: this.mainSelector.visible ?
                              false : this.state.autocompleteVisible
    });
    if (this.props.chicklets.clearAll.onClick) {
     this.props.chicklets.clearAll.onClick();
    }
  }

  renderClearAll() {
    const { chicklets } = this.props;
    if (this.state.selectedItems.length && !this.isChickletNone()) {
      if (this.props.chicklets.clearAll.visible) {
        return (
          <span key='clearAll'
                className={classNames('c-clear-all',
                  {'c-clear-all__pull-right': !chicklets.sortable,
                   'c-clear-all__draggable-container': chicklets.sortable})}
                onClick={this.clearAll}> Clear All
          </span>
        );
      }
    }
  }

  renderKdSelect() {
    return (
      <KdSelect
        setAutocompleteVisibility={this.setAutocompleteVisibility}
        handleRemove={this.handleRemove}
        selectedItems={this.state.selectedItems}
        setSelectedItems={this.setSelectedItems}
        mainSelector={this.mainSelector}
        entityType={this.props.kdFilterModel.getEntityType()}
        isChickletNone={this.isChickletNone()}
        hasInitialValues={this.hasInitialValues()}
        resetSelected={this.resetSelected}
        autoCompleteRenderItemHandler={this.props.autoComplete.onRender}
        events={this.props.events}
        api={this.props.api}
        kdFilterModel={this.props.kdFilterModel}
      />
    );
  }

  renderKdAutocomplete() {
    const {
      autoComplete,
      kdFilterModel,
      api,
      selectBehavior,
      selectedValuesInitial
    } = this.props;
    return (
      <KdAutocomplete
        ref={ref => this.kdAutocomplete = ref}
        handleRemove={this.handleRemove}
        setSelectedItems={this.setSelectedItems}
        setKdSelectEntityLoading={this.setLoading}
        isChickletNone={this.isChickletNone()}
        hasInitialValues={this.hasInitialValues()}
        lastInitialValue={this.lastInitialValue()}
        mainSelector= {this.mainSelector}
        { ...{
            autoComplete,
            api,
            selectBehavior,
            selectedValuesInitial,
            kdFilterModel
          }
        }
      />
    );
  }

  renderKdSelectEntity() {
    return (
      <div>
        {this.mainSelector.visible ? this.renderKdSelect() : null}
        {this.state.autocompleteVisible ? this.renderKdAutocomplete() : null}
      </div>
    );
  }

  render() {
    return (
      <div className='u-1/1'>
        <div
          ref={ref => this.rootElement = ref}
           className={
            classNames(
              'c-kd-select-entity',
              {'u-disabled': this.props.isDisabled }
            )}
        >
          {this.renderKdSelectEntity()}
          {this.renderClearAll()}
          <div className='o-selected__items'>
            {this.renderSelectedItems()}
          </div>
        </div>
      </div>
    );
  }

  // External Functions
  selectedValues() {
    return this.state.selectedItems;
  }
};

KdSelectEntity.propTypes = propTypes;
KdSelectEntity.defaultProps = defaultProps;

export default KdSelectEntity;
