// 核心库
import React, { Component } from 'react'
import { connect } from 'dva'
// 组件库
import { Form, Button } from 'antd'
import IFComponent from '../common/IFComponent'
import UserCustomSearchEditModel from './UserCustomSearchEditModel'
// 工具库
import { isEqual } from 'lodash'
import {
  getDataFieldValue,
  setDataFieldValue
} from '../utils/common'
import storage from '../utils/storage'
import getControl from '../utils/getControl'
import { getFieldConfigs, getRuleByFieldConfigs } from '../utils/getFieldConfigs'

class AdvanceSearch extends Component {
  constructor (props) {
    super(props)
    this.state = {
      data: {},
      fieldConfigs: [],
      isShowContent: false // 展开收起
    }
    // 搜索条件共享与记忆
    const { filterItem = {}, filterList = [], maxShowContentNum = 4 } = props
    const { ID, SHARE_KEY, IS_REMEMBER } = filterItem
    this.insRef = ID // 当前 Search 组件的唯一标识
    this.insRefs = filterList.map(item => item.ID) // 同 filterList 组里面所有的 AdvanceSearch 组件标识
    this.shareKey = SHARE_KEY // 共享数据标识
    this.isRemember = IS_REMEMBER // 是否记忆搜索条件
    // 展开收起阈值
    this.maxShowContentNum = maxShowContentNum
  }

  componentDidMount () {
    const { preventDefaultSearch, onRef, fields, presetValue } = this.props
    // 只在初次加载时，提取本地存储的共享查询条件作为预设值
    this.setFieldConfigs({ fields, presetValue: this.checkPresetValue(presetValue) }, () => {
      !preventDefaultSearch && this.handleSearch()
    })
    onRef instanceof Function && onRef(this)
  }

  UNSAFE_componentWillReceiveProps (nextProps) {
    if (!isEqual(nextProps.fields, this.props.fields) || !isEqual(nextProps.presetValue, this.props.presetValue)) {
      const { fields, presetValue } = nextProps
      this.setFieldConfigs({ fields, presetValue }, this.handleSearch)
    }
  }

  componentWillUnmount () {
    // 组件销毁时清空当前共享实例
    if (this.shareKey) {
      this.props.dispatch({
        type: 'search/cleanShareIns',
        payload: {
          key: this.shareKey,
          insRef: this.insRef
        }
      })
    }
    // 如果不记住查询条件，则组件销毁时，清空共享数据
    if (this.shareKey && !this.isRemember) {
      this.props.dispatch({
        type: 'search/setShareData',
        payload: {
          key: this.shareKey,
          data: []
        }
      })
      storage('session').removeItem(this.shareKey)
    }
  }

  // 相同 formCode 的搜索组件共享搜索条件
  setShareIns = (self = true) => {
    const { search, dispatch } = this.props
    let stopSelfChangeSearch = false
    let stopSelfExtraSearch = false
    if (this.shareKey) {
      const instances = search.shareIns[this.shareKey] || []
      // 同一 filterList 组里面的 Search 组件不共享搜索条件
      const targetIns = instances.filter(ins => ins.insRef !== this.insRef && this.insRefs.indexOf(ins.insRef) === -1)
      if (targetIns.length) {
        // 设置自身状态
        if (self) {
          // 配置的查询条件
          const { instance } = targetIns[0]
          const { fieldConfigs: insFieldConfigs = [], data: insData = {} } = instance.state || {}
          const { fieldConfigs: thisFieldConfigs = [], data: thisData = {} } = this.state
          thisFieldConfigs.forEach(item => {
            // 拥有相同的编码 code 或者 field 字段，就表示查询项需要共享查询条件
            const find = insFieldConfigs.find(ifc => (item.code && ifc.code === item.code) || ifc.field === item.field)
            // 默认显示的查询条件才允许共享查询
            if (find && item.isDefaultQuery) {
              const setValue = getDataFieldValue(insData, find.id)
              if (Object.keys(insData).length) {
                item.value !== setValue && (stopSelfChangeSearch = true)
                item.value = setValue
                thisData[item.id] = setValue
              }
            }
          })
          // 自定义添加的额外查询条件
          const { getExtraData: insGetExtraData } = instance.props || {}
          const { setExtraData: thisSetExtraData, getExtraData: thisGetExtraData } = this.props
          if (insGetExtraData instanceof Function && thisSetExtraData instanceof Function && thisGetExtraData instanceof Function) {
            const insExtraData = insGetExtraData()
            const thisExtraData = thisGetExtraData()
            stopSelfExtraSearch = !isEqual(insExtraData, thisExtraData)
          }
          // 先判断额外搜索条件，额外搜索成立，则调用thisSetExtraData，并在回调中继续调用搜索
          if (stopSelfExtraSearch) {
            thisSetExtraData(insGetExtraData(), this.handleSearch)
          } else if (stopSelfChangeSearch) {
            // fieldConfigs 搜索成立，则调用 setState（因为之前在配置的查询条件中是直接更改 state 的），回调中继续调用搜索
            this.setState({ ...this.state }, this.handleSearch)
          }
        } else {
          // 设置其他关联的Search组件状态
          let stopChangeSearch = false
          let stopExtraSearch = false
          targetIns.forEach(({ instance }) => {
            // 配置的查询条件
            const { fieldConfigs: insFieldConfigs = [], data: insData = {} } = instance.state || {}
            const { fieldConfigs: thisFieldConfigs = [], data: thisData = {} } = this.state
            insFieldConfigs.forEach(item => {
              // 拥有相同的编码 code 或者 field 字段，就表示查询项需要共享查询条件
              const find = thisFieldConfigs.find(tfc => (item.code && tfc.code === item.code) || tfc.field === item.field)
              // 默认显示的查询条件才允许共享查询
              if (find && item.isDefaultQuery) {
                const setValue = getDataFieldValue(thisData, find.id)
                if (Object.keys(thisData).length) {
                  item.value !== setValue && (stopChangeSearch = true)
                  item.value = setValue
                  insData[item.id] = setValue
                }
              }
            })
            // 自定义添加的额外查询条件
            const { setExtraData: insSetExtraData, getExtraData: insGetExtraData } = instance.props || {}
            const { getExtraData: thisGetExtraData } = this.props
            if (thisGetExtraData instanceof Function && insSetExtraData instanceof Function && insGetExtraData instanceof Function) {
              const thisExtraData = thisGetExtraData()
              const insExtraData = insGetExtraData()
              stopExtraSearch = !isEqual(thisExtraData, insExtraData)
            }
            // 先判断额外搜索条件，额外搜索成立，则调用thisSetExtraData，并在回调中继续调用搜索
            if (stopExtraSearch) {
              insSetExtraData(thisGetExtraData(), instance.handleSearch)
            } else if (stopChangeSearch) {
              // fieldConfigs 搜索成立，则调用 setState（因为之前在配置的查询条件中是直接更改 state 的），回调中继续调用搜索
              instance.setState({ ...instance.state }, instance.handleSearch)
            }
          })
        }
      }

      // 存储当前 Search 组件实例
      dispatch({
        type: 'search/setShareIns',
        payload: {
          key: this.shareKey,
          insRef: this.insRef,
          instance: this
        }
      })
      // 存储当前 shareKey 的查询数据
      dispatch({
        type: 'search/setShareData',
        payload: {
          key: this.shareKey,
          data: this.state.fieldConfigs
        }
      })
      storage('session').setItem(this.shareKey, this.state.fieldConfigs)
    }
    return stopSelfChangeSearch || stopSelfExtraSearch
  }

  // 提取本地存储的共享查询条件作为预设值
  checkPresetValue = (presetValue) => {
    const { search } = this.props
    const presetFieldConfigs = search.shareData[this.shareKey] || storage('session').getItem(this.shareKey).val
    const localPreset = {}
    if (Array.isArray(presetFieldConfigs)) {
      presetFieldConfigs.forEach(({ code, field, value }) => {
        // 编码 code 作为查询项共享查询条件的附加标识，因为有些查询项的 field 不一样，但又需要共享查询条件，所以额外配置 code 编码，
        // 当多个查询项拥有相同的编码 code 时，视为这些查询项需要共享查询条件
        code && (localPreset[code] = value)
        field && (localPreset[field] = value)
      })
    }
    return Object.assign(localPreset, presetValue)
  }

  // 处理父组件传下来的 fields
  setFieldConfigs = ({ fields, presetValue }, callback) => {
    const fieldConfigs = []
    if (fields && fields.length) {
      fields.sort((x, y) => x.NUM - y.NUM)
      fields.forEach(item => {
        if (!item.USER_C_C_QUERY_GROUP_ID) {
          const config = getFieldConfigs({
            field: item,
            onLoadData: this.onLoadData,
            onPressEnter: this.onPressEnter,
            onSelect: this.onDropDownPaginationSelect,
            onChange: this.onChange,
            onSearchRef: this.handleSearch
          })
          fieldConfigs.push(config)
        }
      })
    }
    // 赋值 data { field: value }
    const data = {}
    fieldConfigs.forEach(item => {
      if (presetValue !== undefined && typeof presetValue === 'object' && Object.keys(presetValue).length) {
        // 拥有相同编码 code 的查询项共享查询条件
        if (Object.prototype.hasOwnProperty.call(presetValue, item.code)) {
          data[item.id] = presetValue[item.code]
          return
        }
        if (Object.prototype.hasOwnProperty.call(presetValue, item.field)) {
          data[item.id] = presetValue[item.field]
          return
        }
      }
      if (item.defaultValue !== undefined) {
        data[item.id] = item.defaultValue
      }
    })

    this.saveFieldConfigs(fieldConfigs)
    this.setState({
      data,
      fieldConfigs
    }, callback)
  }

  // field change 时候赋值给 data
  onChange = (params) => {
    const { value, colConfig } = params
    const data = { ...this.state.data }
    setDataFieldValue(data, colConfig.id, value)
    this.setState({ data })
  }

  // 提供给分页下拉 下拉树选择 级联组件调用（详见 getControl.js），以获取上述组件的树数据，用于导出 table 时，获取到查询数据，并生成导出标题
  onLoadData = (id, data) => {
    const targetFieldConfig = this.state.fieldConfigs.find(item => item.id === id)
    if (targetFieldConfig) {
      targetFieldConfig.dataSource = data
      this.saveFieldConfigs(this.state.fieldConfigs)
    }
  }

  // 将对应 formCode 的 fieldConfigs 存到 store 中，用于导出 table 时获取到查询数据，并生成导出标题
  saveFieldConfigs = (fieldConfigs) => {
    const { formCode, dispatch } = this.props
    if (formCode) {
      dispatch({
        type: 'search/setFieldConfigs',
        payload: {
          key: formCode,
          data: fieldConfigs
        }
      })
    }
  }

  // 回车搜索
  onPressEnter = ({ e: evt }) => {
    evt.stopPropagation()
    this.handleSearch(false)
  }

  // 提供给分页下拉的回调
  onDropDownPaginationSelect = (params) => {
    const { record, complete, colConfig } = params || {}
    const data = { ...this.state.data }
    setDataFieldValue(data, colConfig.id, record ? record.ID : null)
    setDataFieldValue(data, `selectedRecord.${colConfig.id}`, record)

    this.setState({ data }, () => complete instanceof Function && complete())
  }

  /**
   * 执行搜索，搜索流程为：
   * 调用 Search 组件 onSearch 方法，
   * 然后 Search 分别通过 ref 分别调用 AdvanceSearch 和 SearchGroupField 的 getSearchParams 方法获取到搜索参数，
   * 最后再由 Search 组件完成搜索操作，这样搜索就统一在 Search 中做了
   * @param {*} self 设置自身状态还是设置共享状态
   */
  handleSearch = (self = true) => {
    if (this.setShareIns(self)) return

    const { onSearch } = this.props
    onSearch instanceof Function && onSearch()
  }

  // 获取搜索参数 提供给 ref 调用
  getSearchParams = (rules = [], groups = []) => {
    return getRuleByFieldConfigs(this.state.data, this.state.fieldConfigs, rules, groups,this.props.user)
  }

  render () {
    const { fieldConfigs = [], data, isShowContent } = this.state
    const { formCode, formId, code, iconEle, extraInsertPlace, extraSearch = [], onEditModalClose, onAddGroupConfig } = this.props
    let extraFieldConfigs = extraInsertPlace === 'after' ? fieldConfigs.concat(extraSearch.map(extra => ({ extraSearch: true, extra }))) : extraSearch.map(extra => ({ extraSearch: true, extra })).concat(fieldConfigs)
    extraFieldConfigs = extraFieldConfigs.filter(item => item.isDefaultQuery || item.extraSearch)
    let showFieldConfigs = extraFieldConfigs
    if (showFieldConfigs.length > this.maxShowContentNum - 1) {
      showFieldConfigs = isShowContent ? extraFieldConfigs : extraFieldConfigs.slice(0, this.maxShowContentNum - 1)
    }
    return (
      <Form hideRequiredMark className='opt-search__form'>
        {
          showFieldConfigs.map(item => {
            if (item.extraSearch) return item.extra
            item.value = getDataFieldValue(data, item.id)
            return (
              <Form.Item
                key={item.id}
                label={<>{item.isRequire ? <span style={{ color: 'red' }}>*</span> : null}{item.label}</>}
              >
                {getControl(item, null, this)}
              </Form.Item>
            )
          })
        }
        <div className='opt-search__btns-zone'>
          <IFComponent IF={showFieldConfigs.length}>
            <Button type='primary' onClick={() => this.handleSearch(false)}>查询</Button>
          </IFComponent>
          <div className='opt-search__tool-wrap'>
            <div className='opt-search__children'>{iconEle}</div>
            <Button.Group>
              <UserCustomSearchEditModel
                formCode={formCode}
                formId={formId}
                code={code}
                close={onEditModalClose}
              >
                <Button icon='edit' title='添加自定义查询' size='small' />
              </UserCustomSearchEditModel>
              <Button icon='reload' size='small' title='刷新' onClick={() => this.handleSearch(false)} />
              <Button
                size='small'
                title='新增分组'
                icon='plus'
                onClick={onAddGroupConfig}
              />
              <IFComponent IF={extraFieldConfigs.length >= this.maxShowContentNum}>
                <Button
                  size='small'
                  title='展开收起'
                  icon={isShowContent ? 'up' : 'down'}
                  onClick={() => this.setState({ isShowContent: !isShowContent })}
                />
              </IFComponent>
            </Button.Group>
          </div>
        </div>
      </Form>
    )
  }
}

export default connect(({ search }) => ({ search }))(AdvanceSearch)
