import isFunction from 'lodash/lang/isFunction'
import isObject from 'lodash/lang/isObject'
import forEach from 'lodash/collection/forEach'
import Promise from 'bluebird'

export default function({plugins = {}} = {}) {
  const stack = []

  function dispatch(req, res) {
    return stack.reduce((p, call) => {
      return p.then(() => {
        return call(req, res)
      })
    }, Promise.resolve())
  }

  const dispatcher = (req, res) => {
    return dispatch(req, res)
      .catch(err => {
        if (err.nonce) {
          return
        }

        res
          .status(err.status)
          .json({
            type: err.type,
            message: err.message,
            errors: isObject(err.data) ? err.data : undefined
          })
      })
  }

  function registerPlugin(plugin) {
    if (isFunction(plugin)) {
      return (...spec) => {
        stack.push(plugin(...spec))
        return dispatcher
      }
    }

    if (isObject(plugin)) {
      const container = {}
      forEach(plugin, (name, key) => {
        container[key] = (...spec) => {
          stack.push(name(...spec))
          return dispatcher
        }
      })

      return container
    }

    throw new Error(`The provided plugin has invalid type "${typeof plugin}"`)
  }

  // plugins
  function plugin(name, plugin) {
    if (dispatcher.hasOwnProperty(name)) {
      throw new Error(`The plugin with name ${name} is already registered or would overwrite a builtin method.`)
    }
    Object.defineProperty(dispatcher, name, {
      value: registerPlugin(plugin)
    })

    return dispatcher
  }

  Object.defineProperty(dispatcher, 'plugin', {
    value: plugin
  })

  forEach(plugins, (fn, name) => plugin(name, fn))

  return dispatcher
}

@@ -212,16 +212,17 @@
 = %7B%7D) %7B%0A
+%0A
   const 
@@ -235,24 +235,21 @@
 = %5B%5D%0A%0A  
-function
+const
  dispatc
@@ -241,32 +241,37 @@
   const dispatch
+er = 
 (req, res) %7B%0A   
@@ -267,83 +267,15 @@
  res
-) %7B%0A    return stack.reduce((p, call) =%3E %7B%0A      return p.then((
 ) =%3E %7B%0A
-    
     
@@ -285,119 +285,47 @@
 urn 
-call(req, res)%0A      %7D)%0A    %7D, Promise.resolve())%0A  %7D%0A%0A  const dispatcher = (req, res) =%3E %7B%0A    return dispatch
+Promise%0A      .each(stack, call =%3E call
 (req
@@ -330,16 +330,17 @@
 eq, res)
+)
 %0A      .

use builtin `Promise.each` method