var url = require('url');
var geojsonify = require('../helper/geojsonify');
var _ = require('lodash');

/**
 * Returns a middleware function that converts elasticsearch
 * results into geocodeJSON format.
 *
 * @param {object} [peliasConfig] api portion of pelias config
 * @param {string} [basePath]
 * @returns {middleware}
 */
function setup(peliasConfig, basePath) {

  var opts = {
    config: peliasConfig || require('pelias-config').generate().api,
    basePath: basePath || '/'
  };

  function middleware(req, res, next) {
    return convertToGeocodeJSON(req, res, next, opts);
  }

  return middleware;
}

/**
 * Converts elasticsearch results into geocodeJSON format
 *
 * @param {object} req
 * @param {object} res
 * @param {object} next
 * @param {object} opts
 * @param {string} opts.basePath e.g. '/v1/'
 * @param {string} opts.config.host e.g. 'pelias.mapzen.com'
 * @param {string} opts.config.version e.g. 1.0
 * @returns {*}
 */
function convertToGeocodeJSON(req, res, next, opts) {

  res.body = { geocoding: {} };

  // REQUIRED. A semver.org compliant version number. Describes the version of
  // the GeocodeJSON spec that is implemented by this instance.
  res.body.geocoding.version = '0.2';

  // OPTIONAL. Default: null. The attribution of the data. In case of multiple sources,
  // and then multiple attributions, can be an object with one key by source.
  // Can be a URI on the server, which outlines attribution details.
  res.body.geocoding.attribution = opts.config.attributionURL || url.format({
    protocol: req.protocol,
    host: req.get('host'),
    pathname: 'attribution'
  });

  // OPTIONAL. Default: null. The query that has been issued to trigger the
  // search.
  // Freeform object.
  // This is the equivalent of how the engine interpreted the incoming request.
  // Helpful for debugging and understanding how the input impacts results.
  res.body.geocoding.query = req.clean;

  // remove arrays produced by the tokenizer (only intended to be used internally).
  delete res.body.geocoding.query.tokens_complete;
  delete res.body.geocoding.query.tokens_incomplete;

  // OPTIONAL. Warnings and errors.
  addMessages(req, 'warnings', res.body.geocoding);
  addMessages(req, 'errors', res.body.geocoding);
  addMessages(req, 'debug', res.body.geocoding);

  // OPTIONAL
  // Freeform
  addEngine(opts.config.version, res.body.geocoding);

  // response envelope
  res.body.geocoding.timestamp = new Date().getTime();

  // convert docs to geojson and merge with geocoding block
  _.extend(res.body, geojsonify(req.clean, res.data || []));

  next();
}

function addMessages(req, msgType, geocoding) {
  if (req.hasOwnProperty(msgType) && req[msgType].length) {
    // cleanup arrays to make sure there are no duplicates
    geocoding[msgType] = _.uniq(req[msgType]);
  }
}

function addEngine(version, geocoding) {
  geocoding.engine = {
    name: 'Pelias',
    author: 'Mapzen',
    version: version
  };
}

module.exports = setup;