/* @flow */

import {Component, PropTypes} from 'react';

import StyleKeeper from './style-keeper.js';
import resolveStyles from './resolve-styles.js';

const KEYS_TO_IGNORE_WHEN_COPYING_PROPERTIES = [
  'arguments',
  'callee',
  'caller',
  'length',
  'name',
  'prototype',
  'type'
];

function copyProperties(source, target) {
  Object.getOwnPropertyNames(source).forEach(key => {
    if (
      KEYS_TO_IGNORE_WHEN_COPYING_PROPERTIES.indexOf(key) < 0 &&
      !target.hasOwnProperty(key)
    ) {
      const descriptor = Object.getOwnPropertyDescriptor(source, key);
      Object.defineProperty(target, key, descriptor);
    }
  });
}

function isStateless(component: Function): boolean {
  return !!(!component.render && !(component.prototype && component.prototype.render));
}

export default function enhanceWithRadium(
  configOrComposedComponent: Class<any> | constructor | Function | Object,
  config?: Object = {},
): constructor {
  if (typeof configOrComposedComponent !== 'function') {
    const newConfig = {...config, ...configOrComposedComponent};
    return function(configOrComponent) {
      return enhanceWithRadium(configOrComponent, newConfig);
    };
  }

  const component: Function = configOrComposedComponent;
  let ComposedComponent: constructor = component;

  // Handle stateless components
  if (isStateless(ComposedComponent)) {
    ComposedComponent = class extends Component {
      render() {
        return component(this.props, this.context);
      }
    };
    ComposedComponent.displayName = component.displayName || component.name;
  }

  class RadiumEnhancer extends ComposedComponent {
    _radiumMediaQueryListenersByQuery: {[query: string]: {remove: () => void}};
    _radiumMouseUpListener: {remove: () => void};
    _radiumIsMounted: bool;

    static _isRadiumEnhanced = true;

    constructor() {
      super(...arguments);

      this.state = this.state || {};
      this.state._radiumStyleState = {};
      this._radiumIsMounted = true;
    }

    componentWillUnmount() {
      if (super.componentWillUnmount) {
        super.componentWillUnmount();
      }

      this._radiumIsMounted = false;

      if (this._radiumMouseUpListener) {
        this._radiumMouseUpListener.remove();
      }

      if (this._radiumMediaQueryListenersByQuery) {
        Object.keys(this._radiumMediaQueryListenersByQuery).forEach(
          function(query) {
            this._radiumMediaQueryListenersByQuery[query].remove();
          },
          this
        );
      }
    }

    getChildContext() {
      const superChildContext = super.getChildContext ?
        super.getChildContext() :
        {};

      if (!this.props.radiumConfig) {
        return superChildContext;
      }

      const newContext = {...superChildContext};

      if (this.props.radiumConfig) {
        newContext._radiumConfig = this.props.radiumConfig;
      }

      return newContext;
    }

    render() {
      const renderedElement = super.render();
      let currentConfig = this.props.radiumConfig ||
        this.context._radiumConfig || config;

      if (config && currentConfig !== config) {
        currentConfig = {
          ...config,
          ...currentConfig
        };
      }

      return resolveStyles(this, renderedElement, currentConfig);
    }
  }

  // Class inheritance uses Object.create and because of __proto__ issues
  // with IE <10 any static properties of the superclass aren't inherited and
  // so need to be manually populated.
  // See http://babeljs.io/docs/advanced/caveats/#classes-10-and-below-
  copyProperties(component, RadiumEnhancer);

  if (process.env.NODE_ENV !== 'production') {
    // This also fixes React Hot Loader by exposing the original components top
    // level prototype methods on the Radium enhanced prototype as discussed in
    // https://github.com/FormidableLabs/radium/issues/219.
    copyProperties(ComposedComponent.prototype, RadiumEnhancer.prototype);
  }

  if (RadiumEnhancer.propTypes && RadiumEnhancer.propTypes.style) {
    RadiumEnhancer.propTypes = {
      ...RadiumEnhancer.propTypes,
      style: PropTypes.oneOfType([
        PropTypes.array,
        PropTypes.object
      ])
    };
  }

  RadiumEnhancer.displayName =
    component.displayName ||
    component.name ||
    'Component';

  RadiumEnhancer.contextTypes = {
    ...RadiumEnhancer.contextTypes,
    _radiumConfig: PropTypes.object,
    _radiumStyleKeeper: PropTypes.instanceOf(StyleKeeper)
  };

  RadiumEnhancer.childContextTypes = {
    ...RadiumEnhancer.childContextTypes,
    _radiumConfig: PropTypes.object,
    _radiumStyleKeeper: PropTypes.instanceOf(StyleKeeper)
  };

  return RadiumEnhancer;
}

@@ -702,11 +702,8 @@
 urn 
-!!(
 !com
@@ -771,17 +771,16 @@
 .render)
-)
 ;%0A%7D%0A%0Aexp

remove unneeded cast