'use strict'
let semver = require('semver')

/**
 * Generates a middleware to parse and validate versions out of requestedVersion
 * @param  {object|array} args An object of options, or an array of supported semver versions
 * @return {Middleware}        A middleware that validates the requested version and populates req.version and req.matchedVersion
 */
function validateVersion (args) {
  args = validateArgs(args)
  let options = {
    supportedVersions: args.versions,
    handleUnsupported: args.sendReply ? sendReply.bind(args.versions) : sendError.bind(args.generateError),
    initialVersion: args.isMandatory ? null : '*'
  }
  return addVersion.bind(options)
}

/**
 * Partial middleware that will be extended by validateVersion
 * @param {Request}  req  An expressjs request object
 * @param {Response} res  An expressjs request object
 * @param {function} next A callback that signals the middleware is done processing the request
 */
function addVersion (req, res, next) {
  let requestedVersion = this.initialVersion
  if (req.query.version) requestedVersion = req.query.version
  else if (req.headers['accept-version']) requestedVersion = req.headers['accept-version']

  let matchedVersion = semver.maxSatisfying(this.supportedVersions, requestedVersion)

  if (!matchedVersion) return this.handleUnsupported(req, res, next)
  req.matchedVersion = matchedVersion
  req.version = requestedVersion
  next()
}

/**
 * Validates the options passed to validateVersion and sets default values where required
 * @param  {object} args The options passed to validateVersion
 * @return {object}      The options with default values where necessary
 */
function validateArgs (args) {
  if (Array.isArray(args)) args = {versions: args}

  if (!args.versions) throw new TypeError('Arguments should contain a list of supported versions')
  if (!Array.isArray(args.versions)) throw new TypeError('versions should be a list of strings')
  args.versions.forEach((version) => {
    if (!semver.valid(version)) throw new TypeError(`Version ${version} is not a valid semver string`)
  })

  if (args.sendReply === undefined) args.sendReply = true
  if (typeof args.sendReply !== 'boolean') throw new TypeError('sendReply should be a boolean')

  if (args.isMandatory === undefined) args.isMandatory = false
  if (typeof args.isMandatory !== 'boolean') throw new TypeError('isMandatory should be a boolean')

  if (args.generateError === undefined) args.generateError = generateDefaultError.bind(args.versions)
  if (args.generateError && typeof args.generateError !== 'function') throw new TypeError('generateError should be a function')

  return args
}

/**
 * Call the next middleware with the error generated by this()
 * @this   {function}      A function that will generate the error to be passed into the callback (bound at configuration time)
 * @param  {Request}  req  An expressjs Request object
 * @param  {Response} res  An expressj Response object
 * @param  {function} next The callback to signal that we are done processing the Request
 * @return {undefined}     Returns void
 */
function sendError (req, res, next) {
  next(this())
}

/**
 * Send a reply to the client to indicate that requested version is not Supported
 * @param  {Request}  req An expressjs Request object
 * @param  {Response} res An expressjs Response object
 * @return {undefined}    Returns void
 */
function sendReply (req, res) {
  let output = {
    statusCode: 400,
    title: 'Invalid Version',
    detail: `Supported Versions: [${this.join(', ')}]`
  }
  res.status(400).json(output)
}

/**
 * A default implementation of generateError, to serve as a bound argument in sendError
 * @return {error} An error object with error.status and error.detail set
 */
function generateDefaultError () {
  let error = new Error('Invalid Version')
  error.status = 400
  error.detail = `Supported Versions: [${this.join(', ')}]`
  return error
}

/**
 * Generates a middleware route that routes the request into next() if the version
 * matches and next('route') if the version does not matches
 * @param  {string}  version A semver string
 * @return {function}        A middleware to route requests for this version
 */
function isVersion (version) {
  if (!semver.valid(version)) throw new TypeError(`Version ${version} is not a valid semver string`)
  return routeVersion.bind(version)
}

/**
 * Partial middleware function. Will route requests for the version bound into @this
 * @this   {string}        A semver string (bound by isVersion)
 * @param  {Request}  req  An expressjs Request object
 * @param  {Response} res  An expressjs Response object
 * @param  {function} next A callback to signal that the middleware is done processing the requests
 * @return {undefined}     Returns void
 */
function routeVersion (req, res, next) {
  if (semver.eq(req.matchedVersion, this.toString())) next()
  else next('route')
}

module.exports = {
  isVersion,
  validateVersion
}

@@ -4868,16 +4868,23 @@
 ring()))
+ return
  next()%0A
@@ -4885,20 +4885,22 @@
 ext()%0A  
-else
+return
  next('r

Return when calling the callback