// Copyright IBM Corp. 2016,2018. All Rights Reserved.
// Node module: strong-error-handler
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT

'use strict';

const path = require('path');
const SG = require('strong-globalize');
SG.SetRootDir(path.resolve(__dirname, '..'));
const buildResponseData = require('./data-builder');
const debug = require('debug')('strong-error-handler');
const logToConsole = require('./logger');
const negotiateContentProducer = require('./content-negotiation');

function noop() {
}

/**
 * Create a middleware error handler function.
 *
 * @param {Object} options
 * @returns {Function}
 */
function createStrongErrorHandler(options) {
  options = options || {};

  debug('Initializing with options %j', options);

  // Log all errors via console.error (enabled by default)
  const logError = options.log !== false ? logToConsole : noop;

  return function strongErrorHandler(err, req, res, next) {
    logError(req, err);
    writeErrorToResponse(err, req, res, options);
  };
}

/**
 * Writes thrown error to response
 *
 * @param {Error} err
 * @param {Express.Request} req
 * @param {Express.Response} res
 * @param {Object} options
 */
function writeErrorToResponse(err, req, res, options) {
  debug('Handling %s', err.stack || err);

  options = options || {};

  if (res.headersSent) {
    debug('Response was already sent, closing the underlying connection');
    return req.socket.destroy();
  }

  // this will alter the err object, to handle when res.statusCode is an error
  if (!err.status && !err.statusCode && res.statusCode >= 400)
    err.statusCode = res.statusCode;

  const data = buildResponseData(err, options);
  debug('Response status %s data %j', data.statusCode, data);

  res.setHeader('X-Content-Type-Options', 'nosniff');
  res.statusCode = data.statusCode;

  const sendResponse = negotiateContentProducer(req, warn, options);
  sendResponse(res, data, options);

  function warn(msg) {
    res.header('X-Warning', msg);
    debug(msg);
  }
}

exports = module.exports = createStrongErrorHandler;
exports.writeErrorToResponse = writeErrorToResponse;