/** @jsx createElement */
import { createElement, Component, PropTypes } from 'rax';
import hoistStatics from 'hoist-non-react-statics';
// import pickby from 'lodash.pickby';
import Theme from './theme';

// function throwConnectStyleError(errorMessage, componentDisplayName) {
//   throw Error(
//     `${errorMessage} - when connecting ${componentDisplayName} component to style.`
//   );
// }

// 处理 componentStyle 有多层的情况，例如:
// componentStyle: {
//     Card : {
//         normal:{
//             width:100,
//             height:100
//         },
//         footer:{
//             flex:1
//         }
//     } ,
//     [Card.Item]:{
//         wrap:{
//             backgroundColor:'#cccccc'
//         }
//     },
//     [Card.Item.Button]:{
//         primary:{
//             backgroundColor:'#cccccc'
//         }
//     }
// }
let cacheStatic;
function getTheme(context) {
  if (context.theme) {
    cacheStatic = context.theme;
  }
  // Fallback to a default theme if the component isn't
  // rendered in a StyleProvider.
  // return Theme.get(namespace) || Theme.getDefaultTheme();
  // var a = Theme.get();
  return context.theme || cacheStatic || Theme.getDefaultTheme();
}

/**
 * 过滤，传递需要的样式到子节点
 * @param  {[object]} componentStyle       [样式]
 * @param  {[string]} componentDisplayName [组件名]
 * @param  {[array]} parentPath           [父级路径]
 * @return {[type]}                      [description]
 */
// function injectToChildFilter(
//   componentStyle,
//   componentDisplayName,
//   parentPath = []
// ) {
//   return pickby(componentStyle, (value, key) => {
//     let nextPath = [...parentPath];
//     nextPath.push(componentDisplayName);
//     let maxCurrentStyleKey = nextPath.join('.');
//     //当前 keyPath 是否是currentPath 的子路径， 例如 keyPath : Cart.Item.Button, currentPath: Cart.Item, return true
//     return (
//       key.indexOf(maxCurrentStyleKey) === 0 && key.length > maxCurrentStyleKey
//     );
//   });
// }
/**
 * add display name property in each componeent to prevent being aliasd.
 */
export default (componentStyleProvider = {}, options = {}) => {
  function getComponentDisplayName(WrappedComponent) {
    return WrappedComponent.displayName || WrappedComponent.name || 'Component';
  }

  return function wrapWithStyledComponent(WrappedComponent) {
    const componentDisplayName = getComponentDisplayName(WrappedComponent);

    class StyledComponent extends Component {
      static contextTypes = {
        theme: PropTypes.object,
        parentPath: PropTypes.array,
        namespace: PropTypes.string,
      };

      static childContextTypes = {
        parentPath: PropTypes.array,
        parentStyle: PropTypes.object,
        namespace: PropTypes.string,
      };
      static propTypes = {
        // Element style that overrides any other style of the component
        style: PropTypes.object,
      };
      static WrappedComponent = WrappedComponent;

      constructor(props, context) {
        super(props, context);
        const style = props.style;
        const theme = getTheme(context);
        this.displayName = componentDisplayName;
        const componentStyle = componentStyleProvider(theme.themeStyle);

        this.setWrappedInstance = this.setWrappedInstance.bind(this);

        const finalStyle = this.getFinalStyle(componentStyle, context, style);
        this.state = {
          style: finalStyle,
          componentStyle,
          addedProps: this.resolveAddedProps(),
        };
      }
      getChildContext() {
        return {
          // parentStyle: injectToChildFilter(
          //   this.state.componentStyle,
          //   this.displayName,
          //   this.currentPath
          // ),
          namespace: this.getNamespace(),
          //   this.context.parentStyle :
          //   this.state.childrenStyle,
          // resolveStyle: this.resolveConnectedComponentStyle,
          parentPath: this.getParentPath(),
        };
      }
      componentWillReceiveProps(nextProps, nextContext) {
        const theme = getTheme(nextContext);
        const componentStyle = componentStyleProvider(theme.themeStyle);
        const style = nextProps.style;
        const finalStyle = this.getFinalStyle(componentStyle, nextContext, style);
        this.setState({
          style: finalStyle,
        });
      }

      // getStyleFromKlsName(klassName) {
      //   // console.log(klassName);
      // }
      getFinalStyle(componentStyle, context, style) {
        const currentPath = context.parentPath ? [...context.parentPath] : [];
        currentPath.push(this.displayName);
        let stylesObject = {};
        for (let i = 0; i < currentPath.length; i++) {
          const key = currentPath.slice(currentPath.length - 1 - i).join('.');
          if (componentStyle[key]) {
            stylesObject = { ...stylesObject, ...componentStyle[key] };
          }
        }
        return { ...stylesObject, ...style };
      }

      getParentPath() {
        if (!this.context.parentPath) {
          return [this.displayName];
        }
        return [...this.context.parentPath, this.displayName];
      }
      getNamespace() {
        return this.context.namespace || 'Nuke';
      }

      setNativeProps(nativeProps) {
        if (this.wrappedInstance.setNativeProps) {
          this.wrappedInstance.setNativeProps(nativeProps);
        }
      }

      setWrappedInstance(component) {
        if (component && component._root) {
          this._root = component._root;
        } else {
          this._root = component;
        }
        this.wrappedInstance = this._root;
        this.wrappedInstance &&
          Object.keys(this.wrappedInstance).forEach((attr) => {
            if (!this[attr]) {
              this[attr] = this.wrappedInstance[attr];
            }
          });
      }

      resolveAddedProps() {
        const addedProps = {};
        if (options.withRef) {
          addedProps.ref = 'wrappedInstance';
        }
        return addedProps;
      }

      render() {
        const { addedProps, style } = this.state;
        return <WrappedComponent {...this.props} {...addedProps} themeStyle={style} ref={this.setWrappedInstance} />;
      }
    }
    // return StyledComponent;
    return hoistStatics(StyledComponent, WrappedComponent);
  };
};
