/**
 * Created by baoyinghai on 11/10/16.
 */
import React from 'react';
import { autobind } from 'core-decorators';
import { goBack, replace } from 'react-router-redux';
import renderFuc from './displayComp/index';
import { PFetch } from '../../system/fetch';
import { dispatch } from '../../service/DispatchService';
import { CONTAINER_PRE } from '../../entrance/routes';
import { getValueByKey } from '../../utils/MapUtils';
import { AnHref } from '../info';
import SwitchContainer from './switchContainer';
import { VIEW, EDIT, CONFIRM_SUFFIX } from './constant';
import { BUTTON_POSITION, BUTTON_RELATEDDATA } from '../../constant/dictCodes';
import { isArray } from '../../utils/StringUtils';
import { isEmpty, clone } from '../../utils/EmptyUtils';
import { Form, Input, Col, Icon, Row, Button } from '../../../components/mxa';
import { ExtendButton } from '../../../components';
import { renderColumn } from '../list/util';
import ReviseModal from '../reviseModal';
import { createFunc } from '../../utils/JSExecutor';
import { getMappings } from '../../utils/ModalInputUtils';
import { addEventToBlurForm, removeEventToBlurForm } from '../../utils/EventUtils';

const FormItem = Form.Item;

class Detail extends React.Component {
  /* eslint-disable */
  static propTypes = {
    inject: React.PropTypes.object,
    model: React.PropTypes.oneOf([VIEW, EDIT]).isRequired,
    createRules: React.PropTypes.func, // 自定义表单校验 // record
    beforeSubmit: React.PropTypes.func, // 表单提交之前 // values, callback(v)
    afterSubmit: React.PropTypes.func, // 表单提交之后  //  err
    dataSource: React.PropTypes.object.isRequired,
    renderAnalyser: React.PropTypes.func, // 自定义渲染标单项 // componentName
    renderButtonsSelf: React.PropTypes.func, // 自定义渲染按钮
  };

  static defaultProps = {
    prefixCls: 'mx-list',
  };

  constructor(props) {
    super(props);
    const { dataSource } = this.props;
    const data = this.dataFieldsAdapter(dataSource);
    const modalInputSetting = this.checkModalInputData(dataSource);
    const detailResult = this.dealDataSource(dataSource.detailResult);
    this.dealReadonly();
    this.dealDefaultValue(dataSource, detailResult);
    this.state = {
      dataSource: dataSource,
      passwordDirty: false,
      fields: data,
      detailResult,
      isLeadInto: false,
      modalInputMappings: modalInputSetting.modalInputMappings,
      modalInputIsReadonlys: modalInputSetting.modalInputIsReadonlys
    };
  }

  @autobind
  dealReadonly() {
    const { dataSource, query, readonly } = this.props;
    // if (readonly === true || readonly === 'true' || dataSource.readOnly || query.readonly === true || query.readonly === 'true') {
    if (this.dealBoolean([readonly, dataSource.readOnly, query.readonly, query.displayType === 'VIEW'])) {
      this.props.dataSource.fields.map(item => {
        item.isReadonly = true;
        if (item.displayComponent.componentType === 'MODALINPUT') {
          item.modalInput.disabled = true;
        }
        return item
      });
      // TODO 后面要用privilegeType = COMMON 来处理
      this.props.dataSource.buttons = dataSource.buttons.filter(item => item.privilegeType !== 'EDIT');
      return true;
    } else if (this.props.model === 'VIEW') {
      this.props.dataSource.buttons = dataSource.buttons.filter(item => item.privilegeType !== 'EDIT');
    }
    return false;
  }

  @autobind
  dealBoolean(data) {
    if (data instanceof Array) {
      return data.some(item => {
        if (item === true || item === 'true') {
          return true;
        }
        return false;
      });
    } else {
      return data === true || data === 'true';
    }
  }

  @autobind
  dealDefaultValue(dataSource, detailResult) {
    if (detailResult) {
      this.props.form.setFieldsValue(detailResult);
    }
    !detailResult && dataSource.fields.forEach(item => {
      item.defaultValue && this.props.form.setFieldsValue({ [item.name]: item.defaultValue })
    });
  }

  @autobind
  dealDataSource(detailResult) {
    if (Array.isArray(detailResult)) {
      return detailResult[0];
    }
    return detailResult;
  }

  checkModalInputData(data) {
    let modalInputMappings = [];
    let modalInputIsReadonlys = [];
    data.fields.map((item, index) => {
      if (item.modalInput && getMappings(item.modalInput, this.props)) {
        getMappings(item.modalInput, this.props).map((item1, index1) => {
          modalInputMappings.push(item1.fieldName);
          if (item1.readonly) {
            modalInputIsReadonlys.push(item1.fieldName);
          }
        });
      }
    });
    return { modalInputMappings, modalInputIsReadonlys };
  }

  // 设置显示 和 必填
  @autobind
  changeDataSourceVisable(fieldSetting = {}) {
    const { dataSource } = this.props;
    const fieldList = dataSource.fields && dataSource.fields.map(field => {
        if (fieldSetting[field.name]) {
          const isVisible = fieldSetting[field.name].isVisible;
          if (isVisible === true || isVisible === false) {
            field.isVisible = isVisible;
          }
          if (fieldSetting[field.name].rules) {
            const isRequired = fieldSetting[field.name].rules.isRequired;
            if (isRequired === true || isRequired === false) {
              field.isRequired = isRequired;
            }
          }
          if (fieldSetting[field.name].value !== undefined || fieldSetting[field.name].value !== null) {
            // TODO
            const values = {[field.name]: fieldSetting[field.name].value};
            const detailResult = this.dealDataSource(dataSource.detailResult);
            this.state.detailResult = { ...detailResult, ...values };
            if (fieldSetting[field.name + CONFIRM_SUFFIX]) {
              values[field.name + CONFIRM_SUFFIX] = fieldSetting[field.name + CONFIRM_SUFFIX].value
            }
            this.props.form.setFieldsValue(values);
          }
          if (fieldSetting[field.name].dictionaryFilter) {
            field.dictionaryFilter = fieldSetting[field.name].dictionaryFilter;
          } else {
            delete field.dictionaryFilter;
          }

          if (fieldSetting[field.name].actionLink && field.modalInput) {
            field.modalInput.actionLink = fieldSetting[field.name].actionLink;
          }
        }
        return field;
      });
    const data = { ...dataSource, fields: fieldList};
    this.setState({ fields: this.dataFieldsAdapter(data), dataSource: data });
  }

  // 修改表单默认值
  @autobind
  changeInitValue(value, values) {
    if (!values) {
      const modelInputItem = this.state.fields && this.state.fields[0].filter((item, index) => {
          return item.displayComponent.componentType === 'MODALINPUT';
        });
      const mappingFields = (modelInputItem && modelInputItem[0].modalInput && getMappings(modelInputItem[0].modalInput, this.props)) || [];
      values = {};
      mappingFields && mappingFields.forEach(m => {
        values[m.fieldName] = value && value[m.remoteFieldName];
      });
    }
    const detailResult = this.dealDataSource(this.props.dataSource.detailResult);
    this.state.detailResult = { ...detailResult, ...values };
    this.state.isLeadInto = !!value;
    this.props.form.setFieldsValue(values);
  }

  @autobind
  injectFormValidate(dataSource) {
    if (this.props.inject && this.props.inject.formValidate) {
      return dataSource.fields.map(field => {
        if (this.props.inject.formValidate[field.name]) {
          field.formValidate = this.props.inject.formValidate[field.name];
        }
        return field;
      });
    }
    return dataSource.fields;
  }

  // 注入 过滤 分组
  @autobind
  dataFieldsAdapter(dataSource) {
    const fieldMap = {};
    this.injectFormValidate(dataSource).forEach(f => {
      if (typeof f.groupId === 'string') {
        const groupIdList = f.groupId.split(',');
        const groupNameList = f.groupName.split(',');
        const groupShortNameList = f.groupShortName ? f.groupShortName.split(',') : ['', ''];
        groupIdList.forEach((gId, index) => {
          if (!fieldMap[gId]) {
            fieldMap[gId] = [];
          }
          fieldMap[gId].push({...f,groupId: gId, groupName: groupNameList[index], groupShortName: groupShortNameList[index]});
        });
      } else {
        if (!fieldMap[f.groupId]) {
          fieldMap[f.groupId] = [];
        }
        fieldMap[f.groupId].push(f);
      }
    });
    const ret = [];
    Object.keys(fieldMap).forEach(key => {
      ret.push(fieldMap[key]);
    });
    return ret;
  }

  @autobind
  createReqParam() {
    let params = {};
    if (this.props && this.props.params) {
      params = this.props.params;
    }
    return { ...params, ...getValueByKey(this.props, {}, 'query') };
  }

  @autobind
  realSubmit(func, values) {
    const rest = this.createReqParam();
    const original = this.state.detailResult || {};
    return func && func({ ...original, ...rest, ...values });
  }

  @autobind
  handleSubmit(func, isTemporarySave) {
    const self = this;
    if (isTemporarySave) {
      const requireFields = this.state.fields.filter(item => item.isRequire);
      const fieldNames = [];
      requireFields.forEach(item => {
        if (this.props,form.getFieldValue(item.name)) {
          fieldNames.push(item.name);
        }
      });
      this.props.form.validateFieldsAndScroll(fieldNames, { force: true }, (err, values) => self.validateFieldsCallback(err, values, func));
    } else {
      this.props.form.validateFieldsAndScroll({ force: true }, (err, values) => self.validateFieldsCallback(err, values, func));
    }

  }

  @autobind
  validateFieldsCallback(err, values, func) {
    if (!err) {
      // TODO: deal with checkbox: 'A,B,C'. it's error when not invoke submit
      const fields = (this.props.dataSource && this.props.dataSource.fields) || [];
      fields.filter(field => field.displayComponent.componentType === 'CHECKBOXGROUP').map(f => {
        if (values[f.name]) {
          values[f.name] = values[f.name].split(',');
        } else {
          values[f.name] = [];
        }
      });
      if (this.props.beforeSubmit) {
        this.props.beforeSubmit(values, this.state.detailResult, (v = values) => {
          this.realSubmit(func,  v);
        })
      } else {
        this.realSubmit(func, values);
      }
    }
  }

  @autobind
  handlePasswordBlur(e) {
    const value = e.target.value;
    this.setState({ passwordDirty: this.state.passwordDirty || !!value });
  }

  @autobind
  handleChageState(e) {
    this.props.changeState(e);
  }

  @autobind
  _onSearch(params, item) {
    console.log('***--DETAIL REFRESH--***');
    this.props.onRefresh && this.props.onRefresh(params, item);
  }

  @autobind
  _renderColumnAction(displayPosition) {
    // TODO: refactor
    const { prefixCls, query, inject } = this.props;
    const buttonClass = `${prefixCls}-button`;
    let buttons = (this.props.dataSource.buttons || []).filter(btn => {
      if (displayPosition === BUTTON_POSITION.TOP || displayPosition === BUTTON_POSITION.BOTTOM){
        return (btn && btn.displayPosition) === displayPosition;
      }
      return true;
    });
    buttons = buttons.map(item => {
      if (item.isEditButton) {
        return (
          <a className={buttonClass} onClick={this.props.changeState}>{this.props.model === EDIT ? '返回' : '编辑'}</a>
        );
      } else {
        let ButtonComp = ExtendButton;
        if (this.props.renderButtonsSelf) {
          const myBtn = this.props.renderButtonsSelf(item, this.props);
          if (myBtn) {
            ButtonComp = myBtn;
          }
        }
        return (
          <ButtonComp
            type="link"
            inline={false}
            buttonProps={{
              type: 'primary',
            }}
            {...item}
            disabled={false}
            key={item.buttonDescription}
            className={buttonClass}
            query={query}
            inject={inject}
            submitFuc={item.relatedData === BUTTON_RELATEDDATA.FORM && ((func) => this.handleSubmit(func))}
            onRefresh={params => this._onSearch(params, item)}
            isModal={this.props.isModal}
            modalCallback={this.props.modalCallback}
          />
        );
      }
    });
    if (this.props.modalCallback && displayPosition === BUTTON_POSITION.BOTTOM) {
      buttons = [(<a className={buttonClass + ' cancel-btn'} onClick={this.props.modalCallback}>返回</a>), ...buttons];
    }
    return buttons;
  }

  renderForm(data, fields, i) {
    const titleF = fields[0];
    if (!titleF || !titleF.groupName) return;
    return (
      <SwitchContainer key={titleF.groupName + i} bar={titleF.groupName} index={i}>
        {this.renderGroupItem(data, fields, i)}
      </SwitchContainer>
    );
  }

  getIsSameWithName() {
    return 'ISSAMEWITH';
  }

  // 解析校验 如果是object
  dealWithCheckObject(formValidate, f, ret) {
    const validateType = formValidate.validateType;
    if (validateType === this.getIsSameWithName()) {
      f.formValidate.formItemName = f.name + CONFIRM_SUFFIX;
      ret.push(f);
      //insert a confirm Text
      const fClone = clone(f);
      fClone.name = f.name + CONFIRM_SUFFIX;
      fClone.description = f.description + '确认';
      fClone.formValidate.formItemName = f.name;
      fClone.formValidate.description = f.description;
      ret.push(fClone);
    } else {
      ret.push(f);
    }
  }

  // 解析校验 如果是数组
  dealWithCheckArray(formValidates, f, ret) {
    let flag = true;
    formValidates.some((formValidate, index) => {
      const validateType = formValidate.validateType;
      if (validateType === this.getIsSameWithName()) {
        f.formValidates[index].formItemName = f.name + CONFIRM_SUFFIX;
        ret.push(f);
        const fClone = clone(f);
        fClone.name = f.name + CONFIRM_SUFFIX;
        fClone.description = f.description + '确认';
        fClone.formValidates = [ {
          formItemName: f.name,
          description: f.description,
          validateType: this.getIsSameWithName()
        }];
        ret.push(fClone);
        flag = false;
        return true;
      }
      return false;
    });
    flag && ret.push(f);
  }

  // 特殊情况 二次确认需要自己渲染标单项
  @autobind
  _processFields(fields) {
    fields.map(item => {
      item.isVisible = this.dealIsVisibleField(item);
      // TODO：要添加addonBefore并处理
      if (item.displayComponent.addOnBefore) {
        item.displayComponent.addOnBefore = this.dealAddOnBeforeField(item);
      }
      return item;
    });
    if (this.props.model === VIEW) {
      return fields;
    }
    if (this.props.model === EDIT) {
      const ret = [];
      fields.forEach(f => {
        const formValidate = (f && f.formValidate) || (f && f.formValidates);
        if (isArray(formValidate)) {
          this.dealWithCheckArray(formValidate, f, ret);
        } else if (!isEmpty(formValidate)) {
          this.dealWithCheckObject(formValidate, f, ret);
        } else {
          ret.push(f);
        }
      });
      return ret;
    }
  }

  dealAddOnBeforeField(record) {
    const addOnBefore = record.displayComponent.addOnBefore;
    if (addOnBefore.indexOf('function') !== -1) {
      return createFunc(addOnBefore)(this.props.form.getFieldsValue());
    }
    return addOnBefore;
  }

  @autobind
  dealIsVisibleField(record) {
    if (record.isVisible === 'true') {
      return true;
    } else if (record.isVisible === 'false') {
      return false;
    } else if (record.isVisible !== true && record.isVisible !== false) {
      return createFunc(record.isVisible)(this.props.form.getFieldsValue());
    } else {
      return record.isVisible;
    }
  }

  renderGroupItem(data, fields, groupIndex = 0) {
    const { getFieldDecorator } = this.props.form;
    const isLeadInto = this.state.isLeadInto;
    const changeIsLeadInto = this.changeIsLeadInto;
    const modalInputMappings = this.state.modalInputMappings;
    const modalInputIsReadonlys = this.state.modalInputIsReadonlys;
    return (
      <div className="form-box" >
        <Row className="cell" type="flex" justify="start">
          {this._processFields(fields).map((item, index) => {
            let formItemLayout = {
              labelCol: { span: this.props.model === EDIT ? 22 : 6},
              wrapperCol: { span: this.props.model === EDIT ? 22 : 16 }
            };
            let span = this.props.isModal ? 24 : 12;
            const componentType = getValueByKey(item, 'default', 'displayComponent', 'componentType');
            if (span !== 24 && (componentType === 'TEXTAREA' || componentType === 'TRANSFER' || componentType === 'INNERLIST')) {
              span = 23;
              formItemLayout.wrapperCol = 23;
            }
            // const span = 24;
            const isModalInputMappingItem = modalInputMappings && (modalInputMappings.findIndex((n) => n === item.name) !== -1);
            const modalInputIsReadonly = modalInputIsReadonlys && (modalInputIsReadonlys.findIndex((n) => n === item.name) !== -1);
            return (
              <Col key={item.name + groupIndex} span={item.isVisible ? span : 0}>
                {renderFuc(formItemLayout, item, getFieldDecorator, this.state.detailResult, {...this.props, isLeadInto, isModalInputMappingItem, modalInputIsReadonly}, this.changeDataSourceVisable, this.changeInitValue, this.props.replaceMain)}
              </Col>
            );
          })}
        </Row>
      </div>
    );
  }

  @autobind
  renderBody() {
    // const dataSource = JSON.parse(JSON.stringify(this.state.dataSource));
    const dataSource = clone(this.state.dataSource);
    const fields = this.dataFieldsAdapter(dataSource);
    if (fields && fields.length === 1) {
      return (
        <div style={{ backgroundColor: '#FFFFFF' }}>
          {this.renderGroupItem(dataSource, fields[0])}
        </div>
      );
    } else {
      return fields.map((f, index) => {
        return this.renderForm(dataSource, f, index);
      });
    }
  }

  createButtons(position, tailFormItemLayout) {
    const btns = this._renderColumnAction(position);
    if (this.props.isModal && this.props.createModalButtons) {
      this.props.createModalButtons(btns);
    } else if (position === BUTTON_POSITION.TOP && this.props.createTopButtons) {
      this.props.createTopButtons(btns);
    } else if (btns && btns.length > 0) {
      return (
        <FormItem {...tailFormItemLayout}>
          <div className="button-bar">
            <ul className="button-bar-list">
              {btns && btns.map((item, index) => {
                return (
                  <li key={index}>{item}</li>
                );
              })}
            </ul>
          </div>
        </FormItem>
      );
    }
    return null;
  }

  @autobind
  _renderSummary() {
    // this.state.detailResult
    const values = this.state.detailResult || {};
    const { dataSource } = this.props;
    return dataSource && dataSource.fields && dataSource.fields.filter(field => field.isSummary).map(field => {
        return {
          label: field.description,
          value: renderColumn(values[field.name], field)
        }
      });
  }

  componentDidMount() {
    addEventToBlurForm(window);
  }

  componentWillUnmount() {
    removeEventToBlurForm(window);
  }

  render() {
    const { dataSource } = this.props;
    const tailFormItemLayout = {
      wrapperCol: {
        span: 22,
      },
    };
    if (this.props.renderSummaryHandler) {
      this.props.renderSummaryHandler(this._renderSummary());
    }
    return (
      <div className="detail-container">
        <Form horizontal={true} >
          {this.createButtons(BUTTON_POSITION.TOP, tailFormItemLayout)}
          {this.renderBody()}
          {this.createButtons(BUTTON_POSITION.BOTTOM, tailFormItemLayout)}
        </Form>
        {isArray(dataSource.detailResult) ? (<ReviseModal fieldsData={dataSource.fields} dataSource={dataSource.detailResult} />) : null}
      </div>
    );
  }
}

const detailCreator = () => {
  return Form.create()(Detail);
}

export default detailCreator;

