import moment from 'moment';
import { isDate } from '../../utils/validations.js';


import { DATE_FORMAT_SIMPLE, DATE_FORMAT_WITH_HOUR } from '../../constants';

function getDateFormat(option, showMinTime, showMaxTime) {
  switch (option) {
    case 'Eq':
      return showMinTime ? DATE_FORMAT_WITH_HOUR : DATE_FORMAT_SIMPLE;
    case 'Gt':
      return showMinTime ? DATE_FORMAT_WITH_HOUR : DATE_FORMAT_SIMPLE;
    case 'Lt':
      return showMaxTime ? DATE_FORMAT_WITH_HOUR : DATE_FORMAT_SIMPLE;
    case 'between-min':
      return showMinTime ? DATE_FORMAT_WITH_HOUR : DATE_FORMAT_SIMPLE;
    case 'between-max':
      return showMaxTime ? DATE_FORMAT_WITH_HOUR : DATE_FORMAT_SIMPLE;
    default:
      return DATE_FORMAT_SIMPLE;
  }
}

const baseProto = {
  buildItem(data, showMinTime, showMaxTime) {
    const value = data.target ? data.target.value : data;

    return value ? { value, label: value.format(getDateFormat('Eq', showMinTime, showMaxTime)), option: this.id } : { option: this.id };
  },

  set selected(value) {
    this.selectedObject = this.buildItem(value, this.showMinTime, this.showMaxTime);
    if (this.selectedObject) {
      this.selectedObject.chickletLabel = this.chickletLabel(this.selectedObject.label);
    }

    this.selectedObject.prefix = this.prefix;
  },

  get selected() {
    return this.selectedObject;
  },

  get selectedLabel() {
    return this.selectedObject ? this.selectedObject.label : '';
  },

  get selectedValue() {
    return this.selectedObject ? this.selectedObject.value : '';
  },

  loadDefaultValue() {
    return null;
  },

  chickletLabel(value) {
    const prefix = this.prefix || '';
    return `${prefix} ${String(value)}`;
  },
};

const OptionFactory = {
  create(type, showMinTime, showMaxTime, customLabel) {
    const displayName = customLabel || this.optionsMap[type].displayName;
    const prefix = customLabel ? `${customLabel} ` : this.optionsMap[type].prefix;

    this.optionsMap[type].displayName = displayName;
    this.optionsMap[type].prefix = prefix;

    return Object.assign(
      Object.create(baseProto),
      this.optionsMap[type],
      { key: type, showMinTime, showMaxTime },
    );
  },

  createCustom(option) {
    return Object.assign(
      Object.create(baseProto),
      {
        id: `custom${option.values}`,
        key: `custom${option.values}`,
        displayName: option.label,
        custom: true,
        values: option.values,
        operator: option.operator,
        buildItem() {
          const value = this.operator === 'Between' ? this.values : this.values[0];
          return {
            value,
            label: this.displayName,
            option: this.operator,
            id: this.id,
            custom: true,
          };
        },
        loadDefaultValue() {
          this.selected = option;
          return true;
        },
      }
    );
  },

  optionsMap: {
    Any: {
      id: 'any',
      displayName: 'Any',
      first: true,
    },
    On: {
      id: 'Eq',
      displayName: 'On',
      prefix: 'On',
      first: true,
      buildItem: (value, showMinTime, showMaxTime) => {
        const option = 'Eq';
        return (value ? { value, label: value.format(getDateFormat(option, showMinTime, showMaxTime)), option } : { option });
      },
    },
    After: {
      id: 'Gt',
      displayName: 'After',
      prefix: 'After ',
      first: true,
      buildItem: (value, showMinTime, showMaxTime) => {
        const option = 'Gt';
        return (value ? { value, label: value.format(getDateFormat(option, showMinTime, showMaxTime)), option } : { option });
      },
    },
    Before: {
      id: 'Lt',
      displayName: 'Before',
      prefix: 'Before ',
      first: true,
      buildItem: (value, showMinTime, showMaxTime) => {
        const option = 'Lt';
        return (value ? { value, label: value.format(getDateFormat(option, showMinTime, showMaxTime)), option } : { option });
      },
    },
    Between: {
      id: 'Between',
      displayName: 'Between',
      first: false,
      buildItem: (value, showMinTime, showMaxTime) => {
        if (isDate(value)) {
          return {
            value,
            label: `${value[0].format(getDateFormat('between-min', showMinTime, showMaxTime))}
            - ${value[1].format(getDateFormat('between-max', showMinTime, showMaxTime))}`,
            option: 'Between',
          };
        }

        return { option: 'Between' };
      },
    },
  },
};

function buildChicklet(item, showMinTime, showMaxTime) {
  let option;
  switch (item.operator) {
    case 'Eq':
      option = OptionFactory.optionsMap.On;
      break;
    case 'Gt':
      option = OptionFactory.optionsMap.After;
      break;
    case 'Lt':
      option = OptionFactory.optionsMap.Before;
      break;
    case 'Between':
      option = OptionFactory.optionsMap.Between;
      break;
    default:
      return null;
  }

  if (option === OptionFactory.optionsMap.Between) {
    const values = [
      moment(item.value[0], getDateFormat('between-min', showMaxTime, showMaxTime)),
      moment(item.value[1], getDateFormat('between-max', showMaxTime, showMaxTime)),
    ];

    return {
      chickletLabel: option.buildItem(values, showMinTime, showMaxTime).label,
      option: option.id,
      operator: item.operator,
      value: values,
    };
  }

  // when 'before' or 'after'
  const value = moment(item.value, getDateFormat(option.id, showMaxTime, showMaxTime));
  return ({
    chickletLabel: `${option.prefix || ''}${option.buildItem(value, showMinTime, showMaxTime).label}`,
    option: option.id,
    operator: item.operator,
    value,
  });
}

export function buildChicklets(items, showMinTime, showMaxTime) {
  const chicklets = items
    .map(item => buildChicklet(item, showMinTime, showMaxTime))
    .filter(chicklet => chicklet !== null)
    .reduce((object, chicklet) => (
      Object.assign({}, object, { [chicklet.option]: chicklet })
    ), {});

  return Object.keys(chicklets).map(key => chicklets[key]);
}

export default OptionFactory;

export const isValidOption = option => (
  Object.keys(OptionFactory.optionsMap).indexOf(option) >= 0
);
export const defaultOptions = ['Any', 'On', 'After', 'Before', 'Between'];
