import { mapKeys, toPairs, isUndefined, isString, partial } from 'lodash';
import request from '../utils/request';
import post from '../utils/post';
import { normParams } from '../utils/http-helper';
import { split } from '../utils/filter';
import config from '../utils/config';

const parseFilters = filtersIn => (filtersIn || []).filter(({ filter }) => !!filter).map(({ key, filter }) => [
  split(key, false).map(value => `f-${value}`).join('|'),
  filter,
]);

export const datasourceApi = (coordinate) => {
  const { containerType, containerName, datasourceName } = isString(coordinate) ? {
    containerType: 'global',
    moduleName: coordinate,
  } : (coordinate || {});
  if (containerType === 'global') {
    return {
      query: partial(calcGlobalDatasource, datasourceName),
      count: partial(countGlobalDatasource, datasourceName),
      cursor: partial(cursorGlobalDatasource, datasourceName),
      meta: partial(getGlobalDatasourceMeta, datasourceName),
      update: partial(updateGlobalDatasource, datasourceName),
      create: partial(createGlobalDatasource, datasourceName),
      remove: partial(removeGlobalDatasource, datasourceName),
      validateUpdate: partial(validateUpdateGlobalDatasource, datasourceName),
      validateCreate: partial(validateCreateGlobalDatasource, datasourceName),
      validateRemove: partial(validateRemoveGlobalDatasource, datasourceName),
    };
  } else if (containerType === 'module') {
    return {
      query: partial(calcModuleDatasource, containerName, datasourceName),
      count: partial(countModuleDatasource, containerName, datasourceName),
      cursor: partial(cursorModuleDatasource, containerName, datasourceName),
      meta: partial(getModuleDatasourceMeta, containerName, datasourceName),
      update: partial(updateModuleDatasource, containerName, datasourceName),
      create: partial(createModuleDatasource, containerName, datasourceName),
      remove: partial(removeModuleDatasource, containerName, datasourceName),
      validateUpdate: partial(validateUpdateModuleDatasource, containerName, datasourceName),
      validateCreate: partial(validateCreateModuleDatasource, containerName, datasourceName),
      validateRemove: partial(validateRemoveModuleDatasource, containerName, datasourceName),
    };
  } else {
    throw new Error(`Unsupported containerType: ${containerType}`);
  }
};

const makeQueryParams = ({ pst, psz, filters = [], sortBys = [], sortTypes = [], params = {} }) => {
  let stBy = sortBys.join(',');
  stBy = stBy || undefined;
  let stType = sortTypes.join(',');
  stType = stType || undefined;
  return [
    ...toPairs({ pst, psz, stBy, stType }),
    ...parseFilters(filters),
    ...normParams(mapKeys(params, (v, k) => `p-${k}`)),
  ].filter(v => v && !isUndefined((v[1])));
};

const makeParams = (otherParams, { filters = [], sortBys = [], sortTypes = [], params = {} }) => {
  return [
    ...toPairs(otherParams),
    ...makeQueryParams({ filters, sortBys, sortTypes, params }),
  ].filter(v => v && !isUndefined((v[1])));
};

export async function calcGlobalDatasource(name, { pst, psz, filters = [], sortBys = [], sortTypes = [], params = {}, dmPath }) {
  return request(`${config.apiContextPath}/api/datasource/${name}`, makeParams({ pst, psz, dmPath }, { filters, sortBys, sortTypes, params }));
}

export async function countGlobalDatasource(name, { filters = [], params = {}, dmPath }) {
  return request(`${config.apiContextPath}/api/datasource/${name}/count`, makeParams({ dmPath }, { filters, params }));
}

export async function cursorGlobalDatasource(name, key, params = {}, dmPath) {
  return request(`${config.apiContextPath}/api/datasource/${name}/cursor`, makeParams({ key, dmPath }, { params }));
}

export async function validateUpdateGlobalDatasource(name, key, params = {}, dmPath) {
  return request(`${config.apiContextPath}/api/datasource/${name}/update/validate`, makeParams({ key, dmPath }, { params }));
}

export async function updateGlobalDatasource(name, key, params = {}, dmPath) {
  return post(`${config.apiContextPath}/api/datasource/${name}/update`, {
    key,
    params,
    dmPath,
  });
}

export async function validateCreateGlobalDatasource(name, params = {}, dmPath) {
  return request(`${config.apiContextPath}/api/datasource/${name}/create/validate`, makeParams({ dmPath }, { params }));
}

export async function createGlobalDatasource(name, params = {}, dmPath) {
  return post(`${config.apiContextPath}/api/datasource/${name}/create`, {
    params,
    dmPath,
  });
}

export async function validateRemoveGlobalDatasource(name, key, params = {}, dmPath) {
  return request(`${config.apiContextPath}/api/datasource/${name}/remove/validate`, makeParams({ key, dmPath }, { params }));
}

export async function removeGlobalDatasource(name, key, params = {}, dmPath) {
  return post(`${config.apiContextPath}/api/datasource/${name}/remove`, {
    key,
    params,
    dmPath,
  });
}

export async function getGlobalDatasourceMeta(name) {
  return request(`${config.apiContextPath}/api/datasource/${name}/meta`);
}

export async function calcModuleDatasource(mdName, dsName, { pst, psz, filters = [], sortBys = [], sortTypes = [], params = {}, dmPath }) {
  return request(`${config.apiContextPath}/api/module/user/${mdName}/datasource/${dsName}`, makeParams({ pst, psz, dmPath }, { filters, sortBys, sortTypes, params }));
}

export async function countModuleDatasource(mdName, dsName, { filters = [], params = {}, dmPath }) {
  return request(`${config.apiContextPath}/api/module/user/${mdName}/datasource/${dsName}/count`, makeParams({ dmPath }, { filters, params }));
}

export async function cursorModuleDatasource(mdName, dsName, key, params = {}, dmPath) {
  return request(`${config.apiContextPath}/api/module/user/${mdName}/datasource/${dsName}/cursor`, makeParams({ key, dmPath }, { params }));
}

export async function validateUpdateModuleDatasource(mdName, dsName, key, params = {}, dmPath) {
  return request(`${config.apiContextPath}/api/module/user/${mdName}/datasource/${dsName}/update/validate`, makeParams({ key, dmPath }, { params }));
}

export async function updateModuleDatasource(mdName, dsName, key, params = {}, dmPath) {
  return post(`${config.apiContextPath}/api/module/user/${mdName}/datasource/${dsName}/update`, {
    key,
    params,
    dmPath,
  });
}

export async function validateCreateModuleDatasource(mdName, dsName, params = {}, dmPath) {
  return request(`${config.apiContextPath}/api/module/user/${mdName}/datasource/${dsName}/create/validate`, makeParams({ dmPath }, { params }));
}

export async function createModuleDatasource(mdName, dsName, params = {}, dmPath) {
  return post(`${config.apiContextPath}/api/module/user/${mdName}/datasource/${dsName}/create`, {
    params,
    dmPath,
  });
}

export async function validateRemoveModuleDatasource(mdName, dsName, key, params = {}, dmPath) {
  return request(`${config.apiContextPath}/api/module/user/${mdName}/datasource/${dsName}/remove/validate`, makeParams({ key, dmPath }, { params }));
}

export async function removeModuleDatasource(mdName, dsName, key, params = {}, dmPath) {
  return post(`${config.apiContextPath}/api/module/user/${mdName}/datasource/${dsName}/remove`, {
    key,
    params,
    dmPath,
  });
}

export async function getModuleDatasourceMeta(mdName, dsName) {
  return request(`${config.apiContextPath}/api/module/user/${mdName}/datasource/${dsName}/meta`);
}

