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

import Autocomplete from '../Autocomplete';
import BaseSelect from '../BaseSelect';
import ClearAll from '../ClearAll';
import wrap from '../ItemContainerWrapper';
import options, { defaultOptions, buildCustomOption } from './options';
import { itemHandlerCreator } from '../../utils';
import { ADD_CHICKLET, USER_SPECIFIED_OPTION, ANY } from '../../constants';


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

const propTypes = {
  theme: PropTypes.oneOfType([
    PropTypes.object,
    PropTypes.func,
  ]).isRequired,
  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,
    onFocus: PropTypes.func,
    onBlur: PropTypes.func,
    onLoadingStart: PropTypes.func,
    onLoadingEnd: 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,
  }),

  selectedValuesInitial: PropTypes.array,
};

export class KdSelectEntity extends React.Component {

  constructor(props) {
    super(props);

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

    this.addItem = this.addItem.bind(this);
    this.isInputVisible = this.isInputVisible.bind(this);
    this.onSelectChange = this.onSelectChange.bind(this);
    this.kdFilterOptions = {
      model: this.props.kdFilterModel,
      operator: 'Eq',
      itemHandler: itemHandlerCreator(this.props.kdFilterModel.getDataType()),
    };

    this.state = {
      selectedOption: this.options[0],
      selectedValue: '',
      fireEvents: false,
    };
  }

  componentDidMount() {
    let relatedOption;
    const { userSpecifiedOption } = this.mainSelector.optionValues;

    this.props.onOptionSelected(this.state.selectedOption.id);

    this.props.selectedValuesInitial.forEach(({ value, label }) => {
      if (this.mainSelector.visible) {

        if (userSpecifiedOption.visible) {
          relatedOption = this.options.find(option => option.key === USER_SPECIFIED_OPTION);
          this.addItem({ value, label, inputVisible: true });
        } else {
          relatedOption = this.options.find(option => option.key === value);
        }

        if (relatedOption) {
          relatedOption.selected = { value, label, option: value };
          this.setState({
            selectedOption: relatedOption,
            selectedValue: relatedOption.selectedLabel,
          }, () => this.props.onOptionSelected(this.state.selectedOption.id));
        }
      } else {
        this.addItem({ value, label, inputVisible: true });
      }
    });
    this.setState({ fireEvents: true });
  }

  propBasedOptions() {
    const { kdFilterModel } = this.props;
    const { anyOption, userSpecifiedOption, customOptions } = this.mainSelector.optionValues;
    let initialOptions = [...defaultOptions];
    let optionsFactory = extend(true, {}, options);

    if (!this.mainSelector.visible) {
      return [optionsFactory.create(USER_SPECIFIED_OPTION)];
    }

    if (anyOption.visible) {
      optionsFactory.setAnyDisplayName(anyOption.label
        || `Any ${kdFilterModel.getEntityType()}`);
    } else {
      initialOptions = initialOptions.filter(key => key !== ANY);
    }

    if (userSpecifiedOption.visible) {
      optionsFactory.setUserSpecifiedDisplayName(userSpecifiedOption.label
        || `Search ${kdFilterModel.getEntityType()}(s)...`);
    } else {
      initialOptions = initialOptions.filter(key => key !== USER_SPECIFIED_OPTION);
    }

    return (
      initialOptions
        .map(type => optionsFactory.create(type))
        .concat(
          customOptions
            .map(
              ({ value, label }) => (
                buildCustomOption({ value, label })
              )
            )
        )
    );
  }

  isInputVisible() {
    return (this.state.selectedOption.id === USER_SPECIFIED_OPTION);
  }

  onSelectChange({ target }) {
    const { events } = this.props;
    const selectedOption = this.options.find(option => option.id === target.value);

    if (selectedOption.id === ANY) {
      this.props.onClearChicklets();
    }

    if (selectedOption.loadDefaultValue()) {
      this.props.onItemAdded({ ...selectedOption.selected, kdFilterOptions: this.kdFilterOptions });
      this.Autocomplete.setInputValue();

      if (this.state.fireEvents) {
        const data = {
          value: selectedOption.selected.value,
          label: selectedOption.selectedLabel,
        };
        events.onSelect && events.onSelect({ data });
        events.onChange && events.onChange({ data });
      }
    }

    this.setState({
      selectedOption,
      selectedValue: selectedOption.selectedLabel,
    }, () => this.props.onOptionSelected(this.state.selectedOption.id));
  }

  addItem({ value, label, inputVisible = null }) {
    const { events } = this.props;
    const remove =
      this.props.isChickletNone &&
      this.Autocomplete &&
      this.Autocomplete.setInputValue.bind(this.Autocomplete);

    this.props.onItemAdded({
      value,
      remove,
      chickletLabel: label,
      option: value,
      inputVisible: inputVisible || this.isInputVisible(),
      kdFilterOptions: this.kdFilterOptions,
    });

    if (this.state.fireEvents) {
      events.onChange && events.onChange({ data: { value, label } });
    }
  }


  optionHelper() {
    const {
      theme,
      kdFilterModel,
      api,
      autoComplete,
      isChickletNone,
      search,
      isEntityMultiple,
      isEntityMultipleWithSelector,
      events,
    } = this.props;
    return (
      <div
        className={
          classNames(
            { 'u-hidden': !this.isInputVisible() },
            { [theme['u-hidden']]: !this.isInputVisible() },
          )
        }
      >
        <Autocomplete
          theme={theme}
          ref={ref => this.Autocomplete = ref}
          setSelectedItems={this.addItem}
          handleRemove={this.handleRemove}
          mainSelector={this.mainSelector}
          hasInitialValues={this.props.hasInitialValues()}
          lastInitialValue={this.props.lastInitialValue()}
          {
            ...{
              autoComplete,
              api,
              kdFilterModel,
              isChickletNone,
              search,
              isEntityMultiple,
              isEntityMultipleWithSelector,
              events,
            }
          }
        />
      </div>
    );
  }

  render() {
    const { theme } = this.props;
    return (
      <div
        className={
          classNames(
            { 'u-disabled': this.props.isDisabled },
            { [theme['u-disabled']]: this.props.isDisabled },
          )
        }
      >
        {this.props.mainSelector.visible &&
          <BaseSelect
            theme={theme}
            options={this.options}
            onChange={this.onSelectChange}
            defaultValue={this.state.selectedOption.id}
          />
        }
        {this.optionHelper()}
        {
          !this.props.emptyItems &&
            !this.props.isChickletNone &&
              this.props.chicklets.clearAll.visible &&
            <ClearAll theme={theme} onClick={this.props.onClearChicklets} />
        }
      </div>
    );
  }

}

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

export const UnwrappedKdSelectEntity = KdSelectEntity;

export default wrap(KdSelectEntity);

