'use strict';

/** @jsx createElement */
import { createElement, Component, PropTypes } from 'rax';
import View from 'nuke-view';
import Text from 'nuke-text';
import Image from 'nuke-image';
import Icon from 'nuke-icon';
import BaseInput from 'nuke-base-input';
import { connectStyle } from 'nuke-theme-provider';
import { isWeex } from 'nuke-env';
import { textKeys } from 'nuke-helper';
import stylesProvider from '../styles';

class NormalInput extends Component {
  constructor(props, context) {
    super(props);

    let value = null;
    if ('value' in props) {
      value = props.value;
    } else if ('defaultValue' in props) {
      value = props.defaultValue;
    }
    const count = (value && value.length) || 0;
    this.state = {
      value,
      inputValue: value,
      count: (value && value.length) || 0,
      maxLengthError: count > props.maxLength,
    };
    this.fixedFont = context.commonConfigs && context.commonConfigs.fixedFont;
    if ('fixedFont' in props) {
      this.fixedFont = props.fixedFont;
    }
    [
      'inputHandler',
      'changeHander',
      'clearHandler',
      'focusHandler',
      'blurHandler',
      'getRef',
      'getValue',
      'focus',
      'blur',
      'clear',
    ].forEach((m) => {
      this[m] = this[m].bind(this);
    });
  }
  componentWillReceiveProps(nextProps) {
    if (
      'value' in nextProps &&
      (typeof nextProps.value === 'string' ||
        typeof nextProps.value === 'number') &&
      nextProps.value !== this.state.inputValue
    ) {
      this.setState({
        value: nextProps.value,
        inputValue: nextProps.value,
        count: nextProps.value.length,
        maxLengthError: nextProps.value.length > this.props.maxLength,
      });
    }
  }

  getInput() {
    const {
      readOnly,
      disabled,
      onInput,
      onChange,
      inputStyle = {},
      hasClear,
      rows,
      multiple,
      ...others
    } = this.props;
    const { value } = this.state;
    const styles = this.props.themeStyle;

    const inputAttrs = {
      ...others,
      value: typeof value !== null ? value : null,
      readOnly,
      multiple,
      style: Object.assign(
        {},
        styles['input-ele'],
        hasClear ? styles['input-has-clear'] : null,
        multiple ? styles['multiple-input'] : styles['single-input'],
        inputStyle
      ),
      onInput: this.inputHandler,
      onChange: this.changeHander,
      onFocus: this.focusHandler,
      onBlur: this.blurHandler,
      disabled,
    };
    if (isWeex) {
      // 如果是多行文本，添加 returnKeyType 会导致无法换行
      if (multiple && !this.props.onReturn) {
        delete inputAttrs.onReturn;
        delete inputAttrs.returnKeyType;
      }
    } else if (!disabled) {
      delete inputAttrs.disabled;
    }

    if (multiple) {
      inputAttrs.rows = rows || 3;
    }
    textKeys.map((item) => {
      if (styles[item]) {
        inputAttrs.style[item] = styles[item];
      }
    });
    return (
      <BaseInput
        fixedFont={this.fixedFont}
        {...inputAttrs}
        ref={(n) => {
          this.input = n;
        }}
      />
    );
  }
  clear() {
    this.setState({
      value: '',
      count: 0,
    });
  }
  clearHandler(e) {
    this.setState({
      value: this.state.inputValue,
    });
    this.setState({
      value: '',
      inputValue: '',
      count: 0,
    });

    this.focus();
    this.trigger('onClear', '');
  }

  focusHandler(e) {
    this.setState({
      focus: true,
    });
    this.trigger('onFocus', e);
  }
  trigger(fn, ...attrs) {
    if (typeof fn === 'string') fn = this.props[fn];
    if (!(typeof fn === 'function')) return;

    return fn.apply(this, attrs);
  }
  blurHandler(e) {
    this.setState({
      focus: false,
    });
    this.trigger('onBlur', e);
  }
  focus() {
    this.input.focus();
  }
  getRef() {
    return this.input.getRef();
  }
  blur() {
    this.input.blur();
  }
  getValue() {
    return this.input.getValue();
  }
  changeHander(text, eventObj) {
    const { maxLength } = this.props;
    this.setState({
      value: text,
      inputValue: text,
      count: text.length,
      maxLengthError: text.length > maxLength,
    });
    this.trigger('onChange', text, eventObj);
  }
  inputHandler(text, eventObj) {
    const { maxLength } = this.props;
    this.setState({
      inputValue: text,
      count: text.length,
      maxLengthError: text.length > maxLength,
    });
    this.trigger('onInput', eventObj);
  }
  renderClear(styles) {
    const { count } = this.state;
    const { clearIconStyle = {} } = this.props;
    return count ? (
      <Icon
        name="delete-fill"
        onClick={this.clearHandler}
        style={[styles.clear, clearIconStyle]}
      />
    ) : null;
  }
  renderCustomIcon(styles) {
    const { icon = {} } = this.props;
    const { uri, onPress = () => {}, style = {} } = icon;
    if (!uri) return null;
    return (
      <View style={[styles.icon, style]} onClick={onPress}>
        <Image source={{ uri }} style={[styles['icon-image'], style]} />
      </View>
    );
  }
  renderCount(styles) {
    const { maxLength, multiple, renderCount } = this.props;
    const { maxLengthError } = this.state;
    if (!maxLength || !renderCount) return null;

    const { count } = this.state;
    return (
      <View
        data-role="count"
        style={
          styles[`${multiple ? 'multiple-count-wrap' : 'single-count-wrap'}`]
        }
      >
        <Text
          fixedFont={this.fixedFont}
          style={[
            styles[`${multiple ? 'multiple-count-text' : 'single-count-text'}`],
            maxLengthError ? styles['count-error'] : {},
          ]}
        >
          {count} / {maxLength}
        </Text>
      </View>
    );
  }
  calcInputStyle() {
    const {
      readOnly,
      disabled,
      style = {},
      hideErrorWhenFocus,
      multiple,
      status,
      themeStyle: styles,
    } = this.props;
    const { focus, maxLengthError } = this.state;
    let inputWrapperStyle = Object.assign(
      {},
      styles['input-wrap'],
      styles[`${multiple ? 'multiple-wrap' : 'single-wrap'}`],
      readOnly ? styles.readonly : {},
      status === 'error' ? styles['error-input-wrap'] : {},
      focus ? styles['focus-input-wrap'] : {},
      disabled ? styles[`${multiple ? 'multiple' : 'single'}-disabled`] : {}
    );
    if ((status === 'error' && !hideErrorWhenFocus) || maxLengthError) {
      inputWrapperStyle = Object.assign(
        inputWrapperStyle,
        styles['error-input-wrap']
      );
    }
    if (disabled) {
      inputWrapperStyle = Object.assign(
        inputWrapperStyle,
        styles[`${multiple ? 'multiple' : 'single'}-disabled`]
      );
    }
    return { ...inputWrapperStyle, ...style };
  }
  render() {
    const { renderCount, hasClear, status, errorMessage } = this.props;
    const styles = this.props.themeStyle;
    const { focus } = this.state;

    const inputWrapperStyle = this.calcInputStyle();


    return (
      <View data-role="normal-wrap" style={inputWrapperStyle}>
        {this.getInput()}
        {hasClear ? this.renderClear(styles) : null}
        {!hasClear ? this.renderCustomIcon(styles) : null}
        {(status === 'error' && errorMessage) || renderCount ? (
          <View data-role="help" style={styles.help}>
            {!focus && status === 'error' && errorMessage ? (
              <Text fixedFont={this.fixedFont} style={styles['error-text']}>
                {errorMessage}
              </Text>
            ) : null}
            {this.renderCount(styles)}
          </View>
        ) : null}
      </View>
    );
  }
}
NormalInput.propTypes = {
  defaultValue: PropTypes.any,
  onFocus: PropTypes.func,
  onInput: PropTypes.func,
  onBlur: PropTypes.func,
  onReturn: PropTypes.func,
  placeholder: PropTypes.string,
  readOnly: PropTypes.boolean,
  disabled: PropTypes.boolean,
  style: PropTypes.any,
  maxLength: PropTypes.number,
  multiple: PropTypes.boolean,
  inputStyle: PropTypes.any,
  returnKeyType: PropTypes.any,
  hasClear: PropTypes.boolean,
  rows: PropTypes.number,
  maxRows: PropTypes.number,
  type: PropTypes.oneOf([
    'text',
    'url',
    'password',
    'tel',
    'date',
    'time',
    'email',
  ]),
  status: PropTypes.oneOf(['success', 'error']),
  errorMessage: PropTypes.string,
  renderCount: PropTypes.boolean,
  value: PropTypes.string,
  themeStyle: PropTypes.any,
  hideErrorWhenFocus: PropTypes.boolean,
};
NormalInput.defaultProps = {
  onFocus: () => {},
  onInput: () => {},
  onBlur: () => {},
  onReturn: () => {},
  placeholder: '',
  readOnly: false,
  disabled: false,
  style: {},
  multiple: false,
  inputStyle: {},
  hasClear: false,
  type: 'text',
  status: 'success',
  themeStyle: {},
  renderCount: false,
  placeholderColor: '#999999',
  hideErrorWhenFocus: true,
};
NormalInput.contextTypes = {
  androidConfigs: PropTypes.any,
  commonConfigs: PropTypes.any,
};

NormalInput.displayName = 'Input';
const StyledInput = connectStyle(stylesProvider, { withRef: true })(
  NormalInput
);

export default StyledInput;
