/** @jsx createElement */
import { createElement, findDOMNode, PropTypes, Component } from 'rax';
import { isWeb } from 'nuke-env';
import Mask from 'nuke-mask';
import Touchable from 'nuke-touchable';
import Transition from 'nuke-transition';
import Dimensions from 'nuke-dimensions';
import { connectStyle } from 'nuke-theme-provider';
import stylesProvider from './styles';

const deviceInfo = isWeb ? Dimensions.get('window') : Dimensions.get('screen');
class Slip extends Component {
  constructor(props) {
    super(props);
    this.onVisibleChanged = this.onVisibleChanged.bind(this);
    this.transition = this.transition.bind(this);
    this.show = this.show.bind(this);
    this.hide = this.hide.bind(this);
    this.onMaskShow = this.onMaskShow.bind(this);
    this.onMaskHide = this.onMaskHide.bind(this);
    this.onMaskPress = this.onMaskPress.bind(this);
    this.onPanePress = this.onPanePress.bind(this);
    this.state = {
      visible: props.defaultVisible || false,
      defaultVisible: props.defaultVisible || false,
      scrollPosition: 0,
    };
  }
  onVisibleChanged(e) {
    this.setState({
      visible: e.visible,
    });
  }
  onMaskHide() {
    this.setState({
      visible: false,
    });
    const { onHide } = this.props;
    onHide && onHide();
  }
  onPanePress(e) {
    if (isWeb) {
      e.stopPropagation();
    }
  }
  onMaskShow() {
    const styles = this.calcTransitionStyle(false);
    const box = findDOMNode(this.refs.slipPane);
    setTimeout(() => {
      this.transition(box, styles, () => {
        this.setState({ visible: true });
        const { onShow } = this.props;
        onShow && onShow();
      });
    }, 10);
  }
  onMaskPress() {
    const { maskClosable } = this.props;
    if (!maskClosable) {
      return;
    }
    this.hide();
  }

  getWidthAndHeight() {
    const { direction } = this.props;
    let { width, height } = this.props;

    if (!height && (direction === 'left' || direction === 'right')) {
      height = parseInt(deviceInfo.height, 10);
    }
    if (!width && (direction === 'top' || direction === 'bottom')) {
      width = 750;
    }
    return {
      width,
      height,
    };
  }
  calcTransitionStyle(contentDialogVisualState) {
    const visible = typeof contentDialogVisualState === 'undefined' ? this.state.visible : contentDialogVisualState;
    const { direction } = this.props;
    const { width, height } = this.getWidthAndHeight();
    let transitionStyle = {};
    switch (direction) {
      case 'left':
        transitionStyle = {
          transform: !visible ? `translateX(${width})` : 'translateX(0)',
          webkitTransform: !visible ? `translateX(${width})` : 'translateX(0)',
        };
        break;
      case 'right':
        transitionStyle = {
          transform: !visible ? `translateX(${-width})` : 'translateX(0)',
          webkitTransform: !visible ? `translateX(${-width})` : 'translateX(0)',
        };
        // right
        break;
      case 'top':
        transitionStyle = {
          transform: !visible ? `translateY(${height})` : 'translateX(0)',
          webkitTransform: !visible ? `translateY(${height})` : 'translateX(0)',
        };
        break;
      default:
        transitionStyle = {
          transform: !visible ? `translateY(${-height})` : 'translateX(0)',
          webkitTransform: !visible ? `translateY(${-height})` : 'translateX(0)',
        };
        break;
    }
    return transitionStyle;
  }
  calcInitStyle() {
    const { direction } = this.props;
    const { width, height } = this.getWidthAndHeight();

    let positionObj = {
      position: 'absolute',
      width: `${width}rem`,
      height: `${height}rem`,
    };
    switch (direction) {
      case 'left':
        positionObj = {
          ...positionObj,
          left: `${-width}rem`,
          top: 0,
        };
        break;

      case 'right':
        positionObj = {
          ...positionObj,
          right: `${-width}rem`,
        };
        // right
        break;
      case 'top':
        positionObj = {
          ...positionObj,
          top: `${-height}rem`,
        };
        break;
      default:
        positionObj = {
          ...positionObj,
          bottom: `${-height}rem`,
        };
        break;
    }
    return positionObj;
  }
  transition(box, styles, cb) {
    const { effect, duration } = this.props;
    Transition(
      box,
      styles,
      {
        timingFunction: effect,
        delay: 0,
        duration,
      },
      function () {
        cb && cb.call(this);
      }
    );
  }
  show() {
    // first show mask,
    // then in mask onShow callback, show dialogContent;
    this.refs.BaseSlipMask.show();
    if (isWeb) {
      this.setState({ scrollPosition: window.scrollY });
      document.body.style.position = 'fixed';
      document.body.style.overflow = 'hidden';
    }
  }

  hide() {
    // first hide dialogContent, then hideMask
    const styles = this.calcTransitionStyle(true);
    const box = findDOMNode(this.refs.slipPane);
    setTimeout(() => {
      this.transition(box, styles, () => {
        this.setState({ visible: !this.state.visible });
        this.refs.BaseSlipMask.hide();
      });
    }, 10);
    if (isWeb) {
      document.body.style.position = 'initial';
      document.body.style.overflow = 'initial';
      window.scrollTo(0, this.state.scrollPosition);
    }
  }
  render() {
    const { children, contentStyle } = this.props;
    const styles = this.props.themeStyle;
    return (
      <Mask
        defaultVisible={this.state.defaultVisible}
        animate={false}
        maskClosable={false}
        ref="BaseSlipMask"
        onVisibleChanged={this.onVisibleChanged}
        onShow={this.onMaskShow}
        onHide={this.onMaskHide}
        style={styles.mask}
      >
        <Touchable style={styles['fullscreen-body']} onPress={this.onMaskPress}>
          <Touchable
            ref="slipPane"
            style={[styles.pane, this.calcInitStyle(), contentStyle]}
            onPress={this.onPanePress}
          >
            {children}
          </Touchable>
        </Touchable>
      </Mask>
    );
  }
}
Slip.propTypes = {
  direction: PropTypes.oneOf(['left', 'right', 'top', 'bottom']),
  maskClosable: PropTypes.boolean,
  effect: PropTypes.oneOf(['ease-in', 'ease-in-out', 'ease-out', 'linear', 'cubic-bezier']),
  width: PropTypes.number,
  height: PropTypes.number,

  contentStyle: PropTypes.any,
  duration: PropTypes.number,
};
Slip.defaultProps = {
  direction: 'bottom',
  maskClosable: false,
  effect: 'ease-in-out',
  duration: 200,
  width: 750,
  contentStyle: {},
};
Slip.displayName = 'Slip';

const StyledSlip = connectStyle(stylesProvider)(Slip);

export default StyledSlip;
