/* eslint-disable no-console */
import React, { PropTypes } from 'react';
import { autobind } from 'core-decorators';
import { ExtendButton } from '../../../components';
import { Table, Button, Row, Col, Tooltip, Modal } from '../../../components/mxa';
import { ContentRender } from '../../system/longRunOpt';
import { LIST_SELECTTYPE, BUTTON_POSITION, BUTTON_RELATEDDATA, BUTTON_BINDPARAMETERTYPE } from '../../constant/dictCodes';
import { arr2obj, handleFilterItems, handleOrderItems, renderColumn } from './util';
import { getMenuItemByKeyPaths, getMenuItemByFunc, getMenuItemAndPathByFunc, searchBeforeAndAfter } from '../../utils/MenuHelper';
import SideMenu, { SideMenuContainer } from '../info/sideMenu';
import processMenu from './processMenu';
import { PAGE_TYPE_SUMMARY_LIST } from '../../constant/dictActions';
import ToolBar from './toolBar';
import { isEmpty } from '../../utils/EmptyUtils';
import { trimStart } from '../../utils/StringUtils';
import EditableCell from './editableCell';
import { createFunc } from '../../utils/JSExecutor';
import { isApply, isReview } from '../../utils/ProcessHelper';
import { ProcessButtonCodes } from '../../constant/processButtonCodes';
import { saveProcessMenuCode } from '../../service/SessionStorage';

class ListView extends React.Component {
  static propTypes = {
    prefixCls: PropTypes.string,
    isModal: PropTypes.bool,
    isInfo: PropTypes.bool,
    modalCallback: PropTypes.func,
    inject: PropTypes.object, // inject for customize, key is 'buttonDescription'
    // hiddenSearchBar: PropTypes.bool,
  };

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

  constructor(props) {
    super(props);
    // initial state
    const { domainLink, dataSource, readonly } = this.props;
    this.refStr = 'table-' + new Date().getTime();
    this.isApply = isApply(domainLink);
    this.isReview = isReview(domainLink);
    this.contentList = dataSource.pageResult.contentList || [];
    const initState = { readonly: this.dealReadonly(readonly, dataSource) };
    this.state = this._processData(this.props.dataSource, initState);
    window.scrollTo(0, 0);
  }

  @autobind
  dealReadonly(readonly, dataSource) {
    // TODO 后面要用privilegeType = COMMON 来处理
    if ((readonly === 'true' || readonly === true) || dataSource.readOnly) {
      const buttons = dataSource.buttons.filter(item => item.privilegeType !== 'EDIT');
      this.props.dataSource.buttons = buttons;
      return true;
    }
    return false;
  }

  @autobind
  _renderColumnAction(text, record, buttons, mainEntityKey) {
    const { prefixCls, query, inject } = this.props;
    const toolbarClassName = `${prefixCls}-inline-toolbar`;
    const buttonClassName = `${prefixCls}-inline-button`;
    return (
      <div key="inline-operation" className={toolbarClassName}>
        {
          buttons.map((item, index) => (
            <ExtendButton
              {...item}
              inline={true}
              key={index}
              mainEntityKey={mainEntityKey}
              record={record}
              inject={inject}
              className={buttonClassName}
              query={query}
              onRefresh={this._onSearch}
            />
          ))
        }
      </div>
    );
  }

  _getRowSaveActionName = () => {
    if (this.state.buttons.row && this.state.buttons.row.length > 0) {
      return this.state.buttons.row[0].actionLink;
    }
    return null;
  };

  @autobind
  onCellChange(record, name, editType) {
    return value => {
      // console.log('mainEntityKey:', this.state.mainEntityKey);
      console.log('record', record);
      console.log('name: ', name, ' value: ', value);
      const link = this._getRowSaveActionName();
      if (!link && editType !== 'GLOBAL') {
        console.error('row save link is null');
        return null;
      }
      // TODO: save api
      if (editType === 'GLOBAL') {
        this.changeLocalData(record, name, value);
      } else {
        this.props.exec(() => this.props.fetch(link, { ...record, [name]: value }).then(response => {
          console.log('result: ', response);
        })).then(() => {
          this.changeLocalData(record, name, value);
        });
      }
      return true;
    };
  }

  @autobind
  changeLocalData(record, name, value) {
    const dataSource = this.state.dataSource.map(item => {
      if (item[this.state.mainEntityKey] === record[this.state.mainEntityKey]) {
        return { ...item, [name]: value };
      }
      return item;
    });
    // 修改本地
    this.setState({ dataSource: dataSource });
  }

  @autobind
  _renderColumn(text, fieldContent, record) {
    const temp = renderColumn(text, fieldContent, record);
    const tdRender = (
      <span>{temp}</span>
    );
    // if (typeof temp === 'string' && temp.length > 18) {
    //   tdRender = (
    //     <Tooltip title={temp} placement="top">
    //       <span>{temp.substring(0, 16) + '...'}</span>
    //     </Tooltip>
    //   );
    // }
    return tdRender;
  }

  @autobind
  _filterProcessButton(datas, menuCode) {
    let dataButtons = datas;
    if (dataButtons[0].name) {
      dataButtons = dataButtons.filter(item => ProcessButtonCodes[menuCode].indexOf(item.name) !== -1);
    }
    const buttons = { row: [], top: [] };
    if (dataButtons) {
      buttons.row = dataButtons.filter(item => item.displayPosition === BUTTON_POSITION.ROW);
      buttons.top = dataButtons.filter(item => item.displayPosition === BUTTON_POSITION.TOP);
      buttons.hidden = dataButtons.filter(item => item.displayPosition === BUTTON_POSITION.HIDDEN);
    }
    return buttons;
  }

  @autobind
  _processData(data, initState) {
    const { query, params } = this.props;
    const variantFields = Object.assign({}, query, params);
    const dataButtons = data.buttons;
    let buttons = {};
    if ((this.isApply || this.isReview) && !variantFields.menu) {
      if (this.isApply) {
        variantFields.menu = 'BPMApply.QueryToDo';
        saveProcessMenuCode('BPMApply.QueryToDo');
      } else if (this.isReview) {
        variantFields.menu = 'BPMReview.QueryToDo';
        saveProcessMenuCode('BPMReview.QueryToDo');
      }
      buttons = this._filterProcessButton(dataButtons, variantFields.menu);
    } else {
      buttons = { row: [], top: [] };
      if (dataButtons) {
        buttons.row = dataButtons.filter(item => item.displayPosition === BUTTON_POSITION.ROW);
        buttons.top = dataButtons.filter(item => item.displayPosition === BUTTON_POSITION.TOP);
      }
    }
    // const orderItems = handleOrderItems(data.orderItems);
    const ordered = data.orderItems && data.orderItems.length > 0;
    let mainEntityKey = '';
    const columns = [];
    data.fields && data.fields.sort((a, b) => a.index - b.index).forEach((item, index) => {
      if (item.isMainEntityKey) mainEntityKey = item.name;
      if (this.dealIsVisibleField(item.isVisible)) {
        columns.push({
          width: (item.displayColumnLength || 18) * 12,
          key: index,
          title: item.description,
          dataIndex: item.name,
          // sorter: !!orderItems[item.name],
          render: (text, record) => {
            const fieldContent = this.state.fieldsObject[item.name];
            if (item.editable && !this.state.readonly) {
              return (
                <EditableCell
                  value={text}
                  renderColumn={this._renderColumn}
                  getCurrentRecord={() => this.state.dataSource.find(element => element[this.state.mainEntityKey] === record[this.state.mainEntityKey])}
                  onChange={this.onCellChange(record, item.name, this.props.dataSource.editType)}
                  fieldContent={fieldContent}
                />
              );
            }
            return this._renderColumn(text, fieldContent, record);
          }
        });
      }
    });

    // fix first column
    // if (columns.length > 0) {
    //   columns[0].fixed = true;
    // }

    // add operation
    if (buttons && buttons.row && buttons.row.length > 0) {
      columns.push({
        key: 'inline-operation',
        title: '操作',
        dataIndex: 'inline-operation',
        // fixed: 'right',
        // width: 300,
        render: (text, record) => this._renderColumnAction(text, record, buttons.row, mainEntityKey),
      });
    }

    const pageIndex = data && data.pageResult && data.pageResult.pageIndex;
    const itemsPerPage = data && data.pageResult && data.pageResult.itemsPerPage;
    const pagination = {
      total: data && data.pageResult && data.pageResult.totalItems,
      pageSize: itemsPerPage,
      showSizeChanger: false,
      showQuickJumper: true,
      showTotal: total => `共 ${total} 项`,
    };

    const fieldsObject = arr2obj(data.fields, 'name');
    const filters = handleFilterItems(data.filterItems, fieldsObject);
    const dataSource = this.addKeyForDataSource(data, itemsPerPage);

    const selectedType = data.selectType;
    // const selectedType = this.props.isModal ? LIST_SELECTTYPE.RADIO : data.selectType;
    const selectedRowKeys = [];
    const selectedRows = [];
    dataSource.filter(item => item.isSelected === 'Y').forEach(selectedRow => {
      selectedRowKeys.push(selectedRow[mainEntityKey]);
      selectedRows.push(selectedRow);
    });
    return {
      ...initState,
      columns,
      dataSource,
      buttons,
      pagination,
      fieldsObject,
      filters,
      pageIndex,
      itemsPerPage,
      requestFilterFields: [],
      variantFields,
      ordered,
      orderFields: [],
      mainEntityKey,
      selectedType,
      selectedRowKeys: selectedRowKeys,
      selectedRows: selectedRows,
      advancedSearch: null,
      isAdvance: false, // 查询模式
      y: null, // 控制表格头部fix
      menuTaskCount: this.props.dataSource.pageResult && this.props.dataSource.pageResult.menuTaskCount
    };
  }

  @autobind
  addKeyForDataSource(data, itemsPerPage) {
    return (data.pageResult.contentList && data.pageResult.contentList.map((r, key) => {
      return { key: key + '-' + itemsPerPage, ...r };
    })) || [];
  }

  @autobind
  dealIsVisibleField(isVisible) {
    if (isVisible === 'true') {
      return true;
    } else if (isVisible === 'false') {
      return false;
    } else if (isVisible && isVisible !== false && isVisible !== true) {
      return createFunc(isVisible)();
    }
    return isVisible;
  }

  @autobind
  _onFilterChange(value, isAdvance) {
    console.log(`_onFilterChange ${value}`);
    this.state.requestFilterFields = value;
    this.state.isAdvance = !!isAdvance;
    this.state.pageIndex = 1;
    this._onSearch();
  }

  @autobind
  _onChange(pagination, filters, sorter, isKeepSelectedKeys) {
    console.log('params', pagination, filters, sorter);
    if (this.state.ordered && !isEmpty(sorter)) {
      const orderFields = [];
      orderFields.push({
        orderField: sorter.field,
        orderType: sorter.order === 'descend' ? 'DESC' : 'ASC',
      });

      this.setState({
        pageIndex: pagination.current,
        itemsPerPage: pagination.pageSize,
        orderFields,
      }, () => {
        this._onSearch(isKeepSelectedKeys);
      });
    } else {
      this.setState({
        pageIndex: pagination.current,
        itemsPerPage: pagination.pageSize,
        // orderFields,
      }, () => {
        this._onSearch(isKeepSelectedKeys);
      });
    }
  }

  // isKeepSelectedKeys may be true or object
  @autobind
  _onSearch(isKeepSelectedKeys, isFromAddOrReduce) {
    console.log('***-----LIST REFRESH-----***');
    const searchUrl = trimStart(this.props.domainLink.replace(/^(.*\/)render(\w*)$/, '$1search$2'), '/');
    const param = {
      pageIndex: this.state.pageIndex,
      itemsPerPage: this.state.itemsPerPage,
      requestParamsBean: Object.assign({}, this.state.variantFields, this.state.requestParamsBean), // issue #5
      requestFilterFields: this.state.requestFilterFields,
      requestOrderFields: this.state.orderFields,
      isAdvance: this.state.isAdvance,
    };
    this.props.exec(() => this.props.fetch(searchUrl, param)
      .then(data => {
        if (data.contentList && data.contentList.length === 0 && this.state.pageIndex > 1) {
          // TODO: will not render;
          this.state.pageIndex = this.state.pageIndex - 1;
          param.pageIndex = this.state.pageIndex;
          return this.props.fetch(searchUrl, param);
        }
        return data;
      })
      .then(data => {
        const dataSource = (data.contentList && data.contentList.map((r, key) => {
          return { key: key + '-' + this.state.pageIndex + '-' + r[this.state.mainEntityKey], ...r };
        })) || [];
        this.contentList = data.contentList || [];
        const pagination = {
          current: this.state.pageIndex,
          total: data && data.totalItems,
          pageSize: data.itemsPerPage,
          showSizeChanger: false,
          showQuickJumper: true,
          showTotal: total => `共 ${total} 项`,
        };
        const selectedRowKeys = [];
        const selectedRows = [];
        dataSource.filter(item => item.isSelected === 'Y').forEach(selectedRow => {
          selectedRowKeys.push(selectedRow[this.state.mainEntityKey]);
          selectedRows.push(selectedRow);
        });
        this.setState({
          dataSource,
          pagination,
          selectedRowKeys: selectedRowKeys,
          selectedRows: selectedRows,
          menuTaskCount: this.dealMenuTaskCount(isFromAddOrReduce)
        });
      }));
  }

  @autobind
  dealMenuTaskCount(isFromAddOrReduce) {
    const menuTaskCount = this.state.menuTaskCount;
    if (isFromAddOrReduce) {
      if (isFromAddOrReduce === 'add') {
        menuTaskCount[this.tag.menuCode] = menuTaskCount[this.tag.menuCode] + 1;
      } else {
        menuTaskCount[this.tag.menuCode] = menuTaskCount[this.tag.menuCode] - 1;
      }
    }
    return menuTaskCount;
  }

  @autobind
  _getRelatedState(item) {
    if (item.relatedData === BUTTON_RELATEDDATA.SINGLE) {
      if (this.state.selectedRowKeys.length !== 1) {
        return true;
      }
      const relatedItems = (item.relatedItems && item.relatedItems.relatedItemList) || [];
      const prolog = (item.relatedItems && item.relatedItems.prolog);
      if (prolog === 'AND') {
        return relatedItems.some(this.relatedItemsCallback);
      }
      if (prolog === 'OR') {
        return relatedItems.every(this.relatedItemsCallback);
      }
    }
    if (item.relatedData === BUTTON_RELATEDDATA.MULTIPLE && this.state.selectedRowKeys.length < 1) {
      return true;
    }
    return false;
  }

  @autobind
  relatedItemsCallback(i) {
    if (i.operator === 'greaterThan') {
      return this.state.selectedRows[0][i.relatedKey] <= i.relatedValue;
    } else if (i.operator === 'lessThan') {
      return this.state.selectedRows[0][i.relatedKey] >= i.relatedValue;
    } else if (i.operator === 'greaterOrEqual') {
      return this.state.selectedRows[0][i.relatedKey] < i.relatedValue;
    } else if (i.operator === 'lessOrEqual') {
      return this.state.selectedRows[0][i.relatedKey] > i.relatedValue;
    } else if (i.operator === 'noEqual') {
      return this.state.selectedRows[0][i.relatedKey] === i.relatedValue;
    } else if (i.operator === 'isNull') {
      return !this.state.selectedRows[0][i.relatedKey];
    }
    return this.state.selectedRows[0][i.relatedKey] !== i.relatedValue;
  }

  @autobind
  _renderTopButtons(filter) {
    const { prefixCls, query, inject } = this.props;
    const buttonClass = `${prefixCls}-button`;

    let btnJsonObject = this.state.buttons && this.state.buttons.top && this.state.buttons.top;
    if (filter) {
      btnJsonObject = btnJsonObject.filter(filter);
    }
    const btns = btnJsonObject.map(item => {
      let ButtonComp = ExtendButton;
      if (this.props.renderButtonsSelf) {
        const myBtn = this.props.renderButtonsSelf(item, this.props);
        if (myBtn) {
          ButtonComp = myBtn;
        }
      }
      /* eslint-disable */
      return (
        <ButtonComp
          inline={false}
          buttonProps={{
            type: 'ghost',
          }}
          {...item}
          disabled={this._getRelatedState(item)}
          key={item.buttonDescription}
          mainEntityKey={this.state.mainEntityKey}
          selectedType={this.state.selectedType}
          record={this.props.dataSource.editType === 'GLOBAL' ?
            this.state.dataSource :
            (this.state.variantFields.menu ? this.state.selectedRows.map(item1 => Object.assign(item1, { menuCode: this.state.variantFields.menu })) : this.state.selectedRows)}
          className={buttonClass}
          query={query}
          inject={inject}
          isModal={this.props.isModal}
          modalCallback={this.props.modalCallback}
          onRefresh={() => this.buttonClickOnRefresh(item)}
          clickCallback={() => {
            item.relatedData !== BUTTON_BINDPARAMETERTYPE.NONE && this.refs['toolbar']._switchToolBar();
          }}
          refreshCallback={this.props.refreshCallback}
          readonly={this.state.readonly}
        />
     );
    });
    if (this.props.createTopButtons) {
      this.props.createTopButtons(btns);
      return (<div />);
    }
    return btns;
  }

  @autobind
  buttonClickOnRefresh(item) {
    if (item.name === 'PROCESS_APPLY_ADD') {
      this._onSearch(true, 'add');
    } else {
      if (item.name === 'PROCESS_APPLY_CANCEL') {
        this._onSearch(true, 'reduce');
      } else {
        this._onSearch();
      }
    }
    if (this.props.refreshCallback) {
      this.props.refreshCallback();
    }
  }


  @autobind
  _onRowClick(record, index) {
    if (this.state.selectedType === LIST_SELECTTYPE.INLINE) return;
    console.log('onRowClick ==> ', record, index);

    const selectedIndex = this.state.selectedRowKeys.indexOf(record.key);
    if (selectedIndex > -1) {
      this.setState({
        selectedRowKeys: this.state.selectedRowKeys.filter(item => item !== record.key),
        selectedRows: this.state.selectedRows.filter(item => item.key !== record.key),
      });
    } else if (this.state.selectedType === LIST_SELECTTYPE.RADIO) {
      this.setState({
        selectedRowKeys: [record.key],
        selectedRows: [record],
      });
    } else {
      this.setState({
        selectedRowKeys: this.state.selectedRowKeys.concat(record.key),
        selectedRows: this.state.selectedRows.concat(record),
      });
    }
  }

  renderList(isProcess) {
    // const selectedRows = [];
    const rowSelection = this.state.selectedType === LIST_SELECTTYPE.INLINE ? null : {
      type: this.state.selectedType,
      onChange: (selectedRowKeys, selectedRows) => {
        console.log('onChange ==> ', `selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows);
        this.setState({ selectedRowKeys, selectedRows });
      },
      onSelect: (record, selected) => {
        console.log('onSelect ==> ', record, selected);
        // this.setState({ selectedRows });
      },
      onSelectAll: (selected, selectedRows, changeRows) => {
        console.log('onSelectAll ==> ', selected, selectedRows, changeRows);
        let selectedRowKeys = [];
        if (selected) {
          selectedRowKeys = selectedRows.map(row => row.key);
        }
        this.setState({ selectedRows, selectedRowKeys });
      },
      selectedRowKeys: this.state.selectedRowKeys,
    };

    if (this.state.columns && this.state.columns.length > 0) {
      // console.log('Search[data] ===> ', this.state.filters);
      const { prefixCls } = this.props;
      const listContainer = `${prefixCls}-container`;
      console.log(this.state.selectedRows);
      const columns = this.dealColumns(this.state.columns);
      return (
        <div className={prefixCls + ' ' + this.refStr} style={this.props.customStyle}>
          <ToolBar
            ref="toolbar"
            prefixCls={prefixCls}
            filters={this.state.filters}
            requestFilterFields={[...this.state.requestFilterFields]}
            onSearch={this._onFilterChange}
            renderTopButtons={this._renderTopButtons}
            toolBarType={this.state.selectedRows && this.state.selectedRows.length > 0}
            isModal={this.props.isModalInput || this.props.isModal}
            isProcess={isProcess}
            isInfo={this.props.isInfo}
            modalCallback={this.props.modalCallback}
            selectRows={this.state.selectedRows.length}
            closeCallback={() => {
              this.setState({
                selectedRows: [],
                selectedRowKeys: []
              });
            }}
          />
          <div className={listContainer}>
            <Table
              requestFilterFields={[...this.state.requestFilterFields]}
              locale={{ emptyText: '无符合条件的相关数据' }}
              rowSelection={rowSelection}
              columns={columns}
              dataSource={this.dealListDataSource(this.state.dataSource)}
              sortOrder={false}
              pagination={this.state.pagination}
              onChange={this._onChange}
              onRowClick={this._onRowClick}
              prefixCls="mx-table-self"
              isModal={this.props.isModal}
              scopeStr={this.refStr}
              menuCode={this.tag ? this.tag.menuCode : null}
              refStr={this.props.refStr}
            />
          </div>
        </div>
      );
    }
    console.error('template list', 'columns is null!');
    return (<div />);
  }

  @autobind
  dealListDataSource(dataSource) {
    const { fields } = this.props.dataSource;
    const hasDefaultValueFields = fields.filter(item => item.defaultValue);
    if (hasDefaultValueFields.length > 0) {
      let FieldNames = '';
      const FieldObjects = {};
      hasDefaultValueFields.forEach(item => {
        FieldNames = FieldNames + item.name + ',';
        FieldObjects[item.name] = item.defaultValue;
      });
      dataSource.map((item) => {
        Object.keys(item).forEach(item1 => {
          if (FieldNames.indexOf(item1) >= 0 && !item[item1]) {
            item[item1] = FieldObjects[item1];
          }
        });
        return item;
      });
    }
    return dataSource;
  }

  @autobind
  dealColumns(columns) {
    const fieldsSetting = this.props.dataSource.fieldsSetting;
    if (this.tag && fieldsSetting) {
      const currentMenu = fieldsSetting.filter(item => item.name === this.tag.menuCode);
      const disableFieldsStr = currentMenu && currentMenu.length > 0 && currentMenu[0].fieldNames && currentMenu[0].fieldNames.join(',');
      if (disableFieldsStr) {
        return columns.filter(item => disableFieldsStr.indexOf(item.dataIndex) === -1)
      }
    }
    return columns;
  }

  @autobind
  menuClick(m) {
    saveProcessMenuCode(m.menuCode);
    this.tag = m;
    this.setState({
      requestParamsBean: Object.assign({}, this.state.requestParamsBean, { menu: m.menuCode }),
      buttons: this._filterProcessButton(this.props.dataSource.buttons, m.menuCode),
      variantFields: Object.assign(this.state.variantFields, { menu: m.menuCode }),
      pageIndex: 1,
    }, () => {
      this._onSearch();
    });
  }

  getSideMenu() {
    if (isApply(this.props.domainLink)) {
      return processMenu.apply;
    }
    return processMenu.review;
  }

  componentDidMount() {
    if ((!this.state.dataSource || this.state.dataSource.length === 0) && this.props.dataSource.emptyListPrompt) {
      Modal.error({
        title: '提示',
        content: (<ContentRender message={this.props.dataSource.emptyListPrompt} />)
      });
    }
  }

  componentWillReceiveProps(nextProps) {
    this.setState({
      dataSource: this.addKeyForDataSource(nextProps.dataSource, this.state.itemsPerPage)
    });
  }

  render() {
    const { domainType, domainLink, dataSource, switchNavBar } = this.props;
    const isProcess = (this.isApply || this.isReview) && domainType !== PAGE_TYPE_SUMMARY_LIST;
    let menu = null;
    if (isProcess) {
      menu = this.getSideMenu(domainLink);
      !this.tag && (this.tag = getMenuItemByFunc(m => m.isSelected === true, menu) || {});
    }
    const main = this.renderList(isProcess);
    if (isProcess) {
      setTimeout(() => {
        if (switchNavBar) {
          switchNavBar(false);
        }
      });
      return (
        <div className="info-container">
          <SideMenuContainer>
            <SideMenu
              menu={menu}
              menuClick={this.menuClick}
              selectedItem={this.tag}
              menuTaskCount={this.state.menuTaskCount}
            />
          </SideMenuContainer>
          <div className="main-grid">
            <div className="main_grid_middlle" style={{ height: '100%', backgroundColor: '#e6e9f0' }}>
              {main}
            </div>
          </div>
        </div>
      );
    }
    return main;
  }
}

export default ListView;
