'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 { isWeex } from 'nuke-env';
import { bubbleKeys } from 'nuke-helper';
import BaseInput from 'nuke-base-input';
import TEXTINHERITKEYS from '../mods/inherit-keys';

import IMAGE_URL from '../mods/image';

class Input 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;
    }

    this.inputHandler = this.inputHandler.bind(this);
    this.changeHander = this.changeHander.bind(this);
    this.clearHandler = this.clearHandler.bind(this);
    this.focusHandler = this.focusHandler.bind(this);
    this.blurHandler = this.blurHandler.bind(this);
    this.getRef = this.getRef.bind(this);
    this.getValue = this.getValue.bind(this);
    this.focus = this.focus.bind(this);
    this.blur = this.blur.bind(this);
    this.clear = this.clear.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,
      });
    }
  }
  inputHandler(text, eventObj) {
    const { maxLength } = this.props;
    this.setState({
      // value: text,
      inputValue: text,
      count: text.length,
      maxLengthError: text.length > maxLength,
    });
    this.trigger('onInput', eventObj);
  }
  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);
  }

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

    const inputAttrs = {
      ...others,
      value: typeof value !== null ? value : null,
      readOnly,
      multiple,

      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;
      inputAttrs.style = Object.assign({}, styles['multiple-input-ele']);
      if (inputStyle.height || style.height) {
        inputAttrs.style.height = inputStyle.height || style.height;
      }
      if (inputStyle.lineHeight || style.lineHeight) {
        inputAttrs.style.lineHeight = inputStyle.lineHeight || style.lineHeight;
      }
    } else {
      inputAttrs.style = Object.assign({}, styles['single-input-ele']);
      if (inputStyle.height || style.height) {
        inputAttrs.style.height = inputStyle.height || style.height;
      }

      inputAttrs.style.lineHeight = inputStyle.lineHeight || style.lineHeight || inputAttrs.style.height;
    }
    TEXTINHERITKEYS.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();
  }
  renderClear(styles, height) {
    const { count } = this.state;
    return count ? (
      <View style={[styles.clearWrap, { height }]} onClick={this.clearHandler}>
        <Image
          source={{ uri: IMAGE_URL.clear }}
          // onClick={this.clearHandler}
          style={styles.clear}
        />
      </View>
    ) : null;
  }
  renderCustomIcon(styles, height) {
    const { icon = {} } = this.props;
    const { uri, onPress = () => {}, style = {} } = icon;
    if (!uri) return null;
    return (
      <View style={[styles.icon, { height }, 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 x="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>
    );
  }
  render() {
    const {
      readOnly,
      disabled,
      style = {},
      renderCount,
      hideErrorWhenFocus,
      hasClear,
      multiple,
      status,
      errorMessage,
    } = this.props;
    const styles = this.props.themeStyle;
    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`] : {},

      style
    );
    const customHeight = inputWrapperStyle.height;
    // debugger;
    if ((status === 'error' && !hideErrorWhenFocus) || maxLengthError) {
      inputWrapperStyle = Object.assign(inputWrapperStyle, styles['error-input-wrap']);
    }
    if (disabled) {
      inputWrapperStyle = Object.assign(inputWrapperStyle, styles[`${multiple ? 'multiple' : 'single'}-disabled`]);
    }
    const outerStyle = {};
    bubbleKeys.map((item) => {
      if (item in inputWrapperStyle) {
        outerStyle[item] = inputWrapperStyle[item];
      }
    });
    if (outerStyle.height) {
      delete outerStyle.height;
    }
    if (outerStyle.backgroundColor) {
      delete outerStyle.backgroundColor;
    }

    return (
      <View x="normal-outter" style={outerStyle}>
        <View x="input-wrap" style={inputWrapperStyle}>
          {this.getInput()}
        </View>
        {hasClear ? this.renderClear(styles, customHeight) : null}
        {!hasClear ? this.renderCustomIcon(styles, customHeight) : null}
        {(status === 'error' && errorMessage) || renderCount ? (
          <View x="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>
    );
  }
}
Input.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,
};
Input.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,
};
Input.contextTypes = {
  androidConfigs: PropTypes.any,
  commonConfigs: PropTypes.any,
};

export default Input;
