import axios from 'axios';
import debounce from 'lodash.debounce';
import isequalwith from 'lodash.isequalwith';
import moment from 'moment';
import { Request } 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 class requestHelper {

  constructor({ type, source, onDone, onFail, filters, relatedEntities, beforeSend, delay = 350 }) {
    this.type = type;
    this.source = source;
    this.onDone = onDone;
    this.onFail = onFail;
    this.beforeSend = beforeSend;
    this.getData = debounce(this.delayedGetData, delay);
    this.filters = filters || [];
    this.relatedEntities = relatedEntities;
  }

  fetchFromKD(value) {
    const request = Request('Search', this.source.model.getEntityType());
    request.setUrlBase(this.source.api.url);
    request.setApiKey(this.source.api.key);
    request.setAuthToken(this.source.api.bearerToken);
    request.setAjaxBeforeSend(this.beforeSend);
    request.setAjaxDone(this.onDone);
    request.setAjaxFail(this.onFail);
    request.setPageRows(this.source.api.pageRows || 10);
    request.setQ(value);

    this.filters.forEach((filter) => {
      request.addFilterItem(filter);
    });

    if (this.relatedEntities) {
      request.setRelatedEntities(this.relatedEntities);
    }
    request.requestData();
  }

  fetchFromUrl() {
    axios.get(this.source.url)
      .then(response => (
        this.onDone(response)
      ))
      .catch(error => (
        this.onFail(error)
      ));
  }

  delayedGetData(value = null) {
    switch (this.type) {
      case 'url':
        this.fetchFromUrl(value);
        break;
      case 'data':
        this.onDone(
          this.source.filter(
            ({ label }) =>
              (label.match(new RegExp(value, 'gi')) !== null),
          ),
        );
        break;
      case 'request':
        this.fetchFromKD(value);
        break;
      default:
        break;
    }
  }
}

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 (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':
      // return (
      //   ({ value }) => {
      //     if (Array.isArray(value)) {
      //       return value.map(val => new Date(val));
      //     }
      //     return new Date(value);
      //   }
      // );
    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 (v, operator) => {
        let value = v;
        if (value.length) {
          value = v.replace(/%/g, '').trim();
        }
        return { value, label: value, operator };
      };
    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 };
          }
          return { values: [Number(value)], operator };
        }
      );
    case 'Date':
      // return (
      //   (value, operator) => {
      //     if (Array.isArray(value)) {
      //       return { value: value.map(val => new Date(val)), operator };
      //     }
      //     return { value: new Date(value), operator };
      //   }
      // );
    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 (
          ({ 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)];
    }
  }
  return { selectedValuesInitial: selectedValues };
};

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

export const transformMultipleKdModel = (props) => {
  const { mainSelector: { optionValues: { customOptions } } } = props;
  let parsedOptions = [];
  if (customOptions) {
    parsedOptions = customOptions.map(
      option => ({
        ...option,
        modelOptions: {
          ...option.modelOptions,
          ...parseKdModel(option.modelOptions.kdFilterModel),
        },
      })
    );
  }
  return { mainSelector: { optionValues: { customOptions: 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 a.startOf('day').isSame(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));
  }
}
