import isequalwith from 'lodash/isEqualWith';
import moment from 'moment';
import { FilterItem } from 'karmadata';

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


export function dispatchCustomEvent(elem, eventName, data) {
  const event = new CustomEvent(eventName, { detail: data });
  document.dispatchEvent(event);
}

export function removeLabel(arr, labelToRemove) {
  arr.splice(
    arr.findIndex(
      elem => (
        elem.label === labelToRemove
      )), 1);
  return arr;
}

export function getChickletCategory(entityType) {
  switch (entityType) {
    case KD_COUNTRY:
      return 'orange-darker';
    case KD_STATE:
      return 'orange';
    case KD_CITY:
      return 'orange-lighter';
    default:
      return 'default';
  }
}

export function operatorSelector(dataType) {
  switch (dataType) {
    case 'String':
      return 'Eq';
    case 'Location':
      throw 'Not implemented';
    case 'Geography':
      throw 'Not implemented';
    default:
      return 'Eq';
  }
}

export const itemHandlerCreator = (dataType) => {
  switch (dataType) {
    case 'String':
      return ({ value, operator }) => {
        let res = value;
        if (Array.isArray(value)) {
          return value.map(v => v.replace(/%/g, '').trim());
        } else {
          if (value.length) {
            res = value.replace(/%/g, '').trim();
          }
          if (operator === 'Like') {
            return `%${res}%`;
          }
          return res;
        }
      };
    case 'Location':
      throw 'Not implemented';
    case 'Geography':
      throw 'Not implemented';
    case 'Boolean':
      return ({ value }) => (String(value) === 'true');
    case 'Number':
      return (
        ({ value }) => {
          if (Array.isArray(value)) {
            return value.map(Number);
          }
          return Number(value);
        }
      );
    case 'Date':
    case 'Moment':
      return (
        ({ value }) => {
          if (Array.isArray(value)) {
            return value.map(val => moment(val, DATE_FORMAT_WITH_HOUR));
          }
          return moment(value, DATE_FORMAT_WITH_HOUR);
        }
      );
    default:
      if (dataType) {
        return (
          ({ value, label, entityType }) => (
            {
              KdId: value,
              KdLabel: label,
              EntityType: entityType,
            }
          )
        );
      }
  }
};

const kdValuesToInitialValues = (dataType) => {
  switch (dataType) {
    case 'String':
      return (values, operator) => {
        if (values.length) {
          if (Array.isArray(values)) {
            return values.map(
              val => ({
                values: [val.replace(/%/g, '').trim()],
                label: val,
                operator,
              }),
            );
          }
        }
        return [];
      };
    case 'Location':
      throw 'Not implemented';
    case 'Geography':
      throw 'Not implemented';
    case 'Boolean':
      return value => ({ value: String(value) === 'true' });
    case 'Number':
      return (
        (value, operator) => {
          if (Array.isArray(value)) {
            return [{ values: value.map(Number), operator }];
          }
        }
      );
    case 'Date':
    case 'Moment':
      return (
        (value, operator) => {
          if (Array.isArray(value)) {
            return [{ values: value.map(val => moment(val)), operator }];
          }
          return [{ values: [moment(value)], operator }];
        }
      );
    default:
      if (dataType) {
        return (
          values =>
            values.map(
              ({ KdId, KdLabel, EntityType }) => ({ value: KdId, label: KdLabel, EntityType })
            )
        );
      }
  }
};

const parseKdModel = (model) => {
  let selectedValues = [];

  if (model && model.getFilterItemValue) {
    const { Operator, DataType, Values } = model.getFilterItemValue();
    if (Values.length) {
      selectedValues = kdValuesToInitialValues(DataType)(Values, Operator);
    }
  } else if (model && model.getSortOrderModelValue) {
    selectedValues = model
      .getSortOrderModelValue()
      .map(sort => ({ ...sort, values: [sort.propertyName], label: sort.propertyName }));
  }
  return { selectedValuesInitial: selectedValues, kdFilterModel: model };
};

export const transformKdModel = (props) => {
  const { kdFilterModel } = props;
  if (kdFilterModel) {
    return parseKdModel(kdFilterModel);
  }
};

export const transformMultipleKdModel = (props) => {
  const { mainSelector: { optionGroups } } = props;
  let parsedOptions = [];
  if (optionGroups) {
    parsedOptions = optionGroups.map(
      option => ({
        ...option,
        options: {
          ...option.options,
          ...parseKdModel(option.options.kdFilterModel),
        },
      })
    );
  }
  return { mainSelector: { optionGroups: [...parsedOptions] } };
};

const isDate = date => Object.prototype.toString.call(date) === '[object Date]';

export const compareDate = (a, b) => {
  if (a && b && !Array.isArray(a) && !Array.isArray(b)) {
    if (isDate(a) && isDate(b)) {
      return a.getTime() === b.getTime();
    } else {
      return moment(a).startOf('day').isSame(moment(b).startOf('day'));
    }
  }
};

export function isSameDate(a, b) {
  if (!Array.isArray(a) && !Array.isArray(b)) {
    if (Array.isArray(a.values) && Array.isArray(b.values)) {
      if (b.operator === a.operator) {
        return isequalwith(a.values, b.values, compareDate);
      }
    } else {
      return (
        a.operator === b.operator && compareDate(a.value, b.value)
      );
    }
  }
}

export function getUtcOffset() {
  return -(new Date().getTimezoneOffset() / 60);
}

export function fireEvents(events, data) {
  if (events && events.length) {
    events.forEach(ev => ev && ev(data));
  }
}

export function createFilter(filter) {
  if (filter.getSortOrderModelValue) {
    return filter;
  } else {
    const { Values = [], DataType, EntityType, PropertyName, Operator = 'Eq' } = filter.getFilterItemValue();
    return FilterItem(EntityType, PropertyName, DataType, Operator, Values);
  }
}
