'use strict';

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.fetchRelatedArticlesIfNeeded = fetchRelatedArticlesIfNeeded;
exports.fetchArticlesByUuidIfNeeded = fetchArticlesByUuidIfNeeded;
exports.fetchFeatureArticles = fetchFeatureArticles;

var _index = require('../constants/index');

var _customError = require('../lib/custom-error');

var _normalizr = require('normalizr');

var _index2 = require('../schemas/index');

var _humps = require('humps');

var _index3 = require('../utils/index');

var _lodash = require('lodash');

var _lodash2 = _interopRequireDefault(_lodash);

var _actionTypes = require('../constants/action-types');

var types = _interopRequireWildcard(_actionTypes);

var _isomorphicFetch = require('isomorphic-fetch');

var _isomorphicFetch2 = _interopRequireDefault(_isomorphicFetch);

var _qs = require('qs');

var _qs2 = _interopRequireDefault(_qs);

function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }

function requestArticlesByUuid(id, url) {
  return {
    type: types.FETCH_ARTICLES_BY_GROUP_UUID_REQUEST,
    id: id,
    url: url
  };
}

function failToReceiveArticlesByUuid(id, error) {
  return {
    type: types.FETCH_ARTICLES_BY_GROUP_UUID_FAILURE,
    id: id,
    error: error,
    failedAt: Date.now()
  };
}

function receiveArticlesByUuid(response, id) {
  return {
    type: types.FETCH_ARTICLES_BY_GROUP_UUID_SUCCESS,
    id: id,
    response: response,
    receivedAt: Date.now()
  };
}

function requestRelatedArticles(id, relatedIds, url) {
  return {
    type: types.FETCH_RELATED_ARTICLES_REQUEST,
    id: id,
    relatedIds: relatedIds,
    url: url
  };
}

function failToReceiveRelatedArticles(id, relatedIds, error) {
  return {
    type: types.FETCH_RELATED_ARTICLES_FAILURE,
    id: id,
    relatedIds: relatedIds,
    error: error,
    failedAt: Date.now()
  };
}

function receiveRelatedArticles(response, id, relatedIds) {
  return {
    type: types.FETCH_RELATED_ARTICLES_SUCCESS,
    id: id,
    relatedIds: relatedIds,
    response: response,
    receivedAt: Date.now()
  };
}

function requestFeatureArticles(url) {
  return {
    type: types.FETCH_FEATURE_ARTICLES_REQUEST,
    url: url
  };
}

function failToReceiveFeatureArticles(error) {
  return {
    type: types.FETCH_FEATURE_ARTICLES_FAILURE,
    error: error,
    failedAt: Date.now()
  };
}

function receiveFeaturedArticles(response) {
  return {
    type: types.FETCH_FEATURE_ARTICLES_SUCCESS,
    response: response,
    receivedAt: Date.now()
  };
}

function _buildQuery() {
  var params = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];

  var query = {};
  var whitelist = ['where', 'embedded', 'max_results', 'page', 'sort'];
  _lodash2.default.forEach(whitelist, function (ele) {
    if (params.hasOwnProperty(ele)) {
      if (ele === 'where' || ele === 'embedded') {
        query[ele] = JSON.stringify(params[ele]);
      } else {
        query[ele] = params[ele];
      }
    }
  });
  query = _qs2.default.stringify(query);
  return query;
}

function _buildPostQueryUrl() {
  var params = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];

  var query = _buildQuery(params);
  return (0, _index3.formatUrl)('posts?' + query);
}

function _buildMetaQueryUrl() {
  var params = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];

  var query = _buildQuery(params);
  return (0, _index3.formatUrl)('meta?' + query);
}

function _buildUrl() {
  var params = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
  var target = arguments[1];

  params = params || {};
  params.sort = params.sort || '-publishedDate';
  if (target === 'meta') {
    return _buildMetaQueryUrl(params);
  }
  return _buildPostQueryUrl(params);
}

function _setupWhereInParam(key, value) {
  var params = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2];

  params = params || {};
  value = Array.isArray(value) ? value : [value];
  var where = {};
  if (value.length > 0) {
    _lodash2.default.merge(where, params.where, _defineProperty({}, key, {
      '$in': value
    }));
  }
  params.where = where;
  return params;
}

function _fetchArticles(url) {
  return (0, _isomorphicFetch2.default)(url).then(function (response) {
    var status = response.status;
    if (status === 404) {
      throw new _customError.NotFoundError('Resource are not found by url: ', url);
    } else if (status >= 400) {
      throw new _customError.InternalServerError('Bad response from API, response: ' + JSON.stringify(response));
    }
    return response.json();
  });
}

/* Fetch related articles' meta of one certain article
 * properties of meta: subtitle, name, heroImage, title, topics, publishedDate, slug, links, created and id
 * @param {string} articleId
 * @param {string[]} relatedIds - related article ids
 * @param {object} params - params for composing query param of api
 * @param {string} [params.sort=-publishedDate] -the way returned articles are sorted by
 * @param {object} params.where - where query param
 * @param {object} params.embedded - embedded query param
 * @param {boolean} isOnlyMeta - if true, only get metadata of articles. Otherwise, get full articles.
 */
function fetchRelatedArticlesIfNeeded(articleId, relatedIds) {
  var params = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2];
  var isOnlyMeta = arguments.length <= 3 || arguments[3] === undefined ? true : arguments[3];

  return function (dispatch, getState) {
    if (!articleId) {
      return Promise.resolve();
    }
    var articles = _lodash2.default.get(getState(), ['entities', 'articles'], {});
    var idsToFetch = [];

    _lodash2.default.forEach(relatedIds, function (id) {
      if (!_lodash2.default.has(articles, id)) {
        idsToFetch.push(id);
      }
    });

    if (_lodash2.default.get(idsToFetch, 'length', 0) === 0) {
      return Promise.resolve();
    }

    params = _setupWhereInParam('_id', idsToFetch, params);

    if (!isOnlyMeta) {
      // add default embedded
      params.embedded = params.embedded ? params.embedded : (0, _index3.getArticleEmbeddedQuery)();
    }

    var url = _buildUrl(params, isOnlyMeta ? 'meta' : 'article');
    dispatch(requestRelatedArticles(articleId, idsToFetch, url));
    return _fetchArticles(url).then(function (response) {
      var camelizedJson = (0, _humps.camelizeKeys)(response);
      var normalized = (0, _normalizr.normalize)(camelizedJson.items, (0, _normalizr.arrayOf)(_index2.article));
      return dispatch(receiveRelatedArticles(normalized, articleId, idsToFetch));
    }, function (error) {
      return dispatch(failToReceiveRelatedArticles(articleId, idsToFetch, error));
    });
  };
}

/* Fetch meta of articles according to one group uuid.
 * Group uuid could be Category, Tag or Topic uuid.
 * properties of meta: subtitle, name, heroImage, title, topics, publishedDate, slug, links, created and id
 * @param {string} uuid - Category, Tag or Topic uuid
 * @param {string} type - CATEGORY, TAG or TOPIC
 * @param {object} params - params for composing query param of api
 * @param {string} [params.sort=-publishedDate] -the way returned articles are sorted by
 * @param {object} params.where - where query param
 * @param {object} params.embedded - embedded query param
 * @param {boolean} isOnlyMeta - if true, only get metadata of articles. Otherwise, get full articles.
 */
function fetchArticlesByUuidIfNeeded() {
  var uuid = arguments.length <= 0 || arguments[0] === undefined ? '' : arguments[0];
  var type = arguments.length <= 1 || arguments[1] === undefined ? '' : arguments[1];
  var params = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2];
  var isOnlyMeta = arguments.length <= 3 || arguments[3] === undefined ? true : arguments[3];

  return function (dispatch, getState) {
    if (!uuid || _lodash2.default.get(getState(), ['articlesByUuids', uuid, 'hasMore']) === false) {
      return Promise.resolve();
    }

    switch (type) {
      case _index.CATEGORY:
        params = _setupWhereInParam('categories', [uuid], params);
        break;
      case _index.TAG:
        params = _setupWhereInParam('tags', [uuid], params);
        break;
      case _index.TOPIC:
        params = _setupWhereInParam('topics', [uuid], params);
        break;
      default:
        return Promise.resolve();
    }

    if (!isOnlyMeta) {
      // add default embedded
      params.embedded = params.embedded ? params.embedded : (0, _index3.getArticleEmbeddedQuery)();
    }

    var url = _buildUrl(params, isOnlyMeta ? 'meta' : 'article');
    dispatch(requestArticlesByUuid(uuid, url));
    return _fetchArticles(url).then(function (response) {
      var camelizedJson = (0, _humps.camelizeKeys)(response);
      var normalized = (0, _normalizr.normalize)(camelizedJson.items, (0, _normalizr.arrayOf)(_index2.article));
      _lodash2.default.merge(normalized, { links: camelizedJson.links, meta: camelizedJson.meta });
      return dispatch(receiveArticlesByUuid(normalized, uuid));
    }, function (error) {
      return dispatch(failToReceiveArticlesByUuid(uuid, error));
    });
  };
}

/* Fetch meta of articles whose 'isFeature' field is true
 * properties of meta: subtitle, name, heroImage, title, topics, publishedDate, slug, links, created and id
 * @param {object} params - params for composing query param of api
 * @param {string} [params.sort=-publishedDate] -the way returned articles are sorted by
 * @param {object} params.where - where query param
 * @param {object} params.embedded - embedded query param
 * @param {boolean} isOnlyMeta - if true, only get metadata of articles. Otherwise, get full articles.
 */
function fetchFeatureArticles() {
  var params = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
  var isOnlyMeta = arguments.length <= 1 || arguments[1] === undefined ? true : arguments[1];

  var limit = 6;
  var page = 1;

  return function (dispatch) {
    params = params || {};
    params.where = _lodash2.default.merge({}, params.where, {
      isFeatured: true
    });
    params.max_results = params.max_results || limit;
    params.page = params.page || page;

    var url = _buildUrl(params, isOnlyMeta ? 'meta' : 'article');
    dispatch(requestFeatureArticles(url));
    return _fetchArticles(url).then(function (response) {
      var camelizedJson = (0, _humps.camelizeKeys)(response);
      var normalized = (0, _normalizr.normalize)(camelizedJson.items, (0, _normalizr.arrayOf)(_index2.article));
      return dispatch(receiveFeaturedArticles(normalized));
    }, function (error) {
      return dispatch(failToReceiveFeatureArticles(error));
    });
  };
}

// no need temporarily
/*
function _getListId(target = 'category') {
  if (__DEVELOPMENT__) { // eslint-disable-line
    return target === 'category' ? devCatListId : devTopicListId
  }
  return target === 'category' ? prodCatListId : prodTopicListId
}

export function fetchArticlesByTopicIdNameIfNeeded(topicName = '', params = {} , isOnlyMeta = true) {
  let listId = _getListId('topic')
  let topicId = listId[topicName]
  return fetchArticlesByTopicIdIfNeeded(topicId, params, isOnlyMeta)
}

function _fetchArticlesByListName(name = '', params = {}, isOnlyMeta = true, target) {
  let listId = _getListId(target)
  let id = listId[name]
  params = params || {}
  params.max_results = params.max_results || 10
  params.page = params.page || 1
  return target === 'category' ? fetchArticlesByCatIdIfNeeded(id, params, isOnlyMeta) : fetchArticlesByTagIdIfNeeded(id, params, isOnlyMeta)
}

export function fetchArticlesByCatNameIfNeeded(catName = '', params = {}, isOnlyMeta = true) {
  return _fetchArticlesByListName(catName, params, isOnlyMeta, 'category')
}

export function fetchArticlesByTagNameIfNeeded(tagName = '', params = {}, isOnlyMeta = true) {
  return _fetchArticlesByListName(tagName, params, isOnlyMeta, 'tag')
}

*/