import { enforceValidConfig } from './config'
import invariant from 'invariant'
import partial from './partial'
import React from 'react'

function getDisplayName({displayName}) {
  displayName()
}

function reduce(key, configs, initial, ...args) {
  return configs.reduce((result, config) => {
    const operation = config[key]
    if (typeof operation !== 'function') {
      return result
    }
    return operation(result, ...args)
  }, initial)
}

export function makeDecoratorComponent(configs, BaseComponent) {
  return React.createClass({
    displayName:
      `Decorated(${BaseComponent.displayName})(${configs.map(getDisplayName)})`,

    propTypes: reduce(
      'propTypes',
      configs,
      {...BaseComponent.propTypes}
    ),

    componentWillUnmount() {
      reduce(
        'unmount',
        configs
      )
    },

    getDefaultProps() {
      const {getDefaultProps} = BaseComponent
      return reduce(
        'defaultProps',
        configs,
        typeof getDefaultProps === 'function' ? getDefaultProps() : {}
      )
    },

    getProps() {
      return reduce(
        'nextProps',
        configs,
        {...this.props},
        this.handleNext
      )
    },

    handleNext() {
      this.forceUpdate()
    },

    render() {
      return (
        <BaseComponent
          {...this.getProps()}
        />
      )
    },
  })
}

export function decorateWithConfigs(configs, BaseComponent) {
  invariant(
    Array.isArray(configs),
    'expected `configs` to be an array but got `%s`',
    configs
  )
  return makeDecoratorComponent(
    configs.map(enforceValidConfig),
    BaseComponent
  )
}

export default function decorate(...configs) {
  return partial(decorateWithConfigs, configs)
}

@@ -141,20 +141,17 @@
 unction 
-getD
+d
 isplayNa
@@ -157,40 +157,174 @@
 ame(
-%7BdisplayName%7D) %7B%0A  displayName()
+configs, BaseComponent) %7B%0A  const decoratorNames = configs.map((%7BdisplayName%7D) =%3E displayName())%0A  return %60Decorated($%7BBaseComponent.displayName%7D)($%7BdecoratorNames%7D)%60
 %0A%7D%0A%0A
@@ -332,22 +332,21 @@
 unction 
-reduce
+pluck
 (key, co
@@ -354,26 +354,8 @@
 figs
-, initial, ...args
 ) %7B%0A
@@ -382,19 +382,16 @@
 uce((res
-ult
 , config
@@ -405,26 +405,57 @@
     
-const operation = 
+if (config.hasOwnProperty(key)) %7B%0A      res.push(
 conf
@@ -465,88 +465,145 @@
 key%5D
+)
 %0A    
-if (typeof operation !== 'function') %7B%0A      return result%0A    %7D
+%7D%0A    return res%0A  %7D, %5B%5D)%0A%7D%0A%0Afunction reduce(operations, initial, ...args) %7B%0A  return operations.reduce(
 %0A    
+(
 re
-turn
+sult, operation) =%3E
  ope
@@ -629,21 +629,21 @@
 rgs)
+,
 %0A  
-%7D,
+ 
  initial
 )%0A%7D%0A
@@ -638,16 +638,19 @@
  initial
+%0A  
 )%0A%7D%0A%0Aexp
@@ -707,24 +707,117 @@
 omponent) %7B%0A
+  const nextProps = pluck('nextProps', configs)%0A  const unmounts = pluck('unmount', configs)%0A
   return Rea
@@ -853,42 +853,9 @@
 ame:
-%0A      %60Decorated($%7BBaseComponent.
+ 
 disp
@@ -865,43 +865,32 @@
 Name
-%7D)($%7B
+(
 configs
-.map(getDisplayName)%7D)%60
+, BaseComponent)
 ,%0A%0A 
@@ -917,16 +917,22 @@
 (%0A      
+pluck(
 'propTyp
@@ -939,22 +939,16 @@
 es',
-%0A     
  configs
 ,%0A  
@@ -935,32 +935,33 @@
 pTypes', configs
+)
 ,%0A      %7B...Base
@@ -1035,50 +1035,16 @@
 uce(
-%0A        'unmount',%0A        configs%0A      
+unmounts
 )%0A  
@@ -1148,16 +1148,22 @@
         
+pluck(
 'default
@@ -1169,32 +1169,24 @@
 tProps',
-%0A       
  configs
 ,%0A      
@@ -1169,32 +1169,33 @@
 tProps', configs
+)
 ,%0A        typeof
@@ -1313,17 +1313,16 @@
         
-'
 nextProp
@@ -1326,26 +1326,8 @@
 rops
-',%0A        configs
 ,%0A  

make the decorator a little more efficient