// 核心库
import React, { Component } from 'react'
import { connect } from 'dva'
// 组件库
import { Row, Col, Select, TreeSelect, Button, Collapse, Icon } from 'antd'
import IFComponent from '../common/IFComponent'
// 工具库
import { getDataFieldValue, setDataFieldValue, initFilter, guid } from '../utils/common'
import getControl from '../utils/getControl'
import { getFieldConfigs, getGroupByGroupConfigs } from '../utils/getFieldConfigs'
import { isEqual } from 'lodash'

const Option = Select.Option
const Panel = Collapse.Panel
const TreeSelectNode = TreeSelect.TreeNode
// dateType 对应 controlType
const dataMapControl = { 2: 7, 3: 3, 4: 4, 5: 10, 6: 12, 8: 17, 9: 18, 10: 19, 11: 9, 12: 20, 13: 21, 14: 11, 15: 22, 16: 23, 17: 2 }

const digGroupData = (arr, target) => {
  for (let i = 0, j = arr.length; i < j; i++) {
    if (arr[i].id === target) return arr[i]
    if (Array.isArray(arr[i].childGroups) && arr[i].childGroups.length) {
      const result = digGroupData(arr[i].childGroups, target)
      if (result) return result
    }
  }
}

const operator1 = [
  { value: 1, label: '等于' },
  { value: 2, label: '不等于' },
  { value: 7, label: '开始于' },
  { value: 8, label: '结束于' },
  { value: 9, label: '包含' }
]

const operator3 = [
  { value: 1, label: '等于' },
  { value: 2, label: '不等于' }
]

const operator7 = [
  { value: 1, label: '等于' },
  { value: 2, label: '不等于' },
  { value: 3, label: '小于' },
  { value: 4, label: '小于或等于' },
  { value: 5, label: '大于' },
  { value: 6, label: '大于或等于' }
]

function PanelContent (props) {
  // 新增一组字段
  const addFieldConfig = () => {
    const { code, config, customConfigId, onChange, onPressEnter } = props
    !config.fieldConfigs && (config.fieldConfigs = [])
    config.fieldConfigs.push({
      id: guid(),
      searchGroupId: config.id,
      isSysQueryField: false,
      userCCQueryId: customConfigId || null,
      code,
      onChange,
      data: {
        onPressEnter
      }
    })
    props.onPanelContentChange instanceof Function && props.onPanelContentChange()
  }

  // 删除一组字段
  const deleteFieldConfig = (id) => {
    const { config } = props
    const findIndex = config.fieldConfigs.findIndex(item => item.id === id)
    if (findIndex !== -1) {
      config.fieldConfigs.splice(findIndex, 1)
      props.onPanelContentChange instanceof Function && props.onPanelContentChange()
    }
  }

  // 字段选择
  const onSelectChange = (id, nodeData) => {
    const dataType = getDataFieldValue(nodeData, 'DataType')
    const controlType = dataMapControl[dataType] ? dataMapControl[dataType] : 1

    // 配置出选中的配置
    const fieldConfig = {
      field: getDataFieldValue(nodeData, 'FieldName'),
      label: getDataFieldValue(nodeData, 'ShowLabel'),
      controlType,
      dataType,
      operator: controlType === 1 ? '9' : '1',
      isCustom: getDataFieldValue(nodeData, 'IsCustom'),
      isSysParam: getDataFieldValue(nodeData, 'IsSysParam'),
      defaultValue: null,
      isSysQueryField: getDataFieldValue(nodeData, 'IsSysField', false),
      caseType: getDataFieldValue(nodeData, 'CaseType'),
      isRequire: getDataFieldValue(nodeData, 'IsRequire')
    }

    // 获取到当前选中项
    const { config } = props
    const find = config.fieldConfigs.find(item => item.id === id)
    if (find) {
      Object.keys(fieldConfig).forEach(key => {
        // 重写当前选中项各项值为选中的配置
        setDataFieldValue(find, key, getDataFieldValue(fieldConfig, key))
        !find.data && (find.data = {})
        find.data.enumName = getDataFieldValue(nodeData, 'EnumName')
      })
      props.onPanelContentChange instanceof Function && props.onPanelContentChange()
    }
  }

  // 操作关系选择
  const onOperatorChange = (id, value) => {
    const { config } = props
    const find = config.fieldConfigs.find(item => item.id === id)
    if (find) {
      find.operator = value ? value.toString() : ''
      props.onPanelContentChange instanceof Function && props.onPanelContentChange()
    }
  }

  // 构造树节点
  const getFieldTreeNode = (data) => {
    return data.filter(item => !item.IsCustom).map(item => {
      if (item.Children) {
        return (
          <TreeSelectNode
            title={item.Label}
            key={item.FieldName}
            value={item.FieldName}
            data={item}
            isLeaf={item.IsLeaf}
          >
            {getFieldTreeNode(item.Children)}
          </TreeSelectNode>
        )
      }
      return (
        <TreeSelectNode
          title={<>{item.IsRequire ? <span style={{ color: 'red' }}>*</span> : null}{item.Label}</>}
          key={item.FieldName}
          value={item.FieldName}
          data={item}
          isLeaf={item.IsLeaf}
        />
      )
    })
  }

  // TreeSelect 远程数据加载
  const handleLoadChildTreeNode = (treeNode) => {
    const { login, formId, dispatch } = props
    const { data } = treeNode.props
    if (data.Children) return Promise.resolve()

    const json = initFilter(login.OrgId, formId, 'CREATE_TIME', 0, 1, data.FieldName, data.TypeName, data.Label)
    return dispatch({
      type: 'search/getQueryFields',
      payload: json
    }).then(ret => {
      treeNode.props.data.Children = ret
    })
  }

  const { data, config, queryFields } = props
  const { fieldConfigs = [], childGroups = [] } = config
  return (
    <>
      <IFComponent
        IF={fieldConfigs.length}
        ELSE={
          <Button
            icon='plus'
            type='dashed'
            shape='circle'
            title='新增条件'
            onClick={addFieldConfig}
            style={{ marginLeft: 12 }}
          />
        }
      >
        {
          fieldConfigs.map((item, index) => {
            item.value = getDataFieldValue(data, item.id)
            const options = item.controlType === 1 ? operator1 : item.controlType === 3 ? operator3 : item.controlType === 7 ? operator7 : []
            return (
              <Row gutter={16} key={item.id} style={{ marginBottom: 6 }}>
                <Col span={6}>
                  <TreeSelect
                    allowClear
                    showSearch
                    value={item.field}
                    placeholder='请选择字段'
                    treeNodeFilterProp='title'
                    loadData={handleLoadChildTreeNode}
                    onSelect={(value, node) => onSelectChange(item.id, node.props.data)}
                    onChange={value => !value && onSelectChange(item.id, null)}
                    dropdownStyle={{
                      maxHeight: 400,
                      overflow: 'auto'
                    }}
                    style={{ width: '100%' }}
                  >
                    {getFieldTreeNode(queryFields)}
                  </TreeSelect>
                </Col>
                <IFComponent IF={!!item.field}>
                  <Col span={3}>
                    <IFComponent IF={options.length}>
                      <Select
                        allowClear
                        value={item.operator ? +item.operator : null}
                        onChange={val => onOperatorChange(item.id, val)}
                      >
                        {options.map(option => <Option value={option.value} key={option.id + option.value}>{option.label}</Option>)}
                      </Select>
                    </IFComponent>
                  </Col>
                  <Col span={6}>{getControl(item)}</Col>
                </IFComponent>
                <Col span={3}>
                  <Button
                    icon='delete'
                    type='danger'
                    shape='circle'
                    title='删除'
                    onClick={() => deleteFieldConfig(item.id)}
                  />
                  <IFComponent IF={index === fieldConfigs.length - 1}>
                    <Button
                      icon='plus'
                      type='dashed'
                      shape='circle'
                      title='新增条件'
                      onClick={addFieldConfig}
                      style={{ marginLeft: 12 }}
                    />
                  </IFComponent>
                </Col>
              </Row>
            )
          })
        }
      </IFComponent>
      <IFComponent IF={childGroups.length}>
        <SearchGroupField
          {...props}
          key={childGroups.map(item => item.id).join(';') || guid()}
          childField
          groups={childGroups}
        />
      </IFComponent>
    </>
  )
}

function PanelHeader (props) {
  const { app, config, index, onSelectChange, deleteGroupConfig, addGroupConfig } = props
  const enumOptions = app.enums && app.enums['FMUserCCQueryGroupRelationTypeEnum'] && app.enums['FMUserCCQueryGroupRelationTypeEnum'].options

  return (
    <div className='opt-search__collapseHeader'>
      <span>条件组{index + 1}</span>
      <div className='opt-search__collapseHeaderSelect'>
        <span>分组关系</span>
        <Select
          value={config.relationType}
          onChange={onSelectChange}
          size='small'
          style={{ width: 60 }}
        >
          {(enumOptions || []).map(option => <Option key={option.value} value={option.value}>{option.label}</Option>)}
        </Select>
      </div>
      <div className='opt-search__collapseHeaderAction'>
        <Icon
          type='delete'
          title='删除该分组'
          style={{ color: '#f00', marginRight: 15 }}
          onClick={deleteGroupConfig}
        />
        <Icon
          type='plus'
          title='新增分组'
          onClick={addGroupConfig}
        />
      </div>
    </div>
  )
}
const CPanelHeader = connect(({ app }) => ({ app }))(PanelHeader)

class SearchGroupField extends Component {
  // 注意：该组件作为循环嵌套使用的子组件时，state 值均为父组件 state 的值的引用，无需 cloneDeep
  constructor (props) {
    super(props)
    this.state = {
      data: {},
      groupConfigs: [],
      queryFields: []
    }
  }

  componentDidMount () {
    // 如果是 PanelContent 中渲染出来的该组件，那么可以直接拿 groups 属性作为 groupConfigs
    if (this.props.childField) {
      this.setState({
        data: this.props.data,
        groupConfigs: this.props.groups,
        queryFields: this.props.queryFields
      })
      return
    }
    this.getQueryFields()
    const { onRef, fields, groups, presetValue } = this.props
    this.setGroupConfigs({ fields, groups, presetValue })
    onRef instanceof Function && onRef(this)
  }

  UNSAFE_componentWillReceiveProps (nextProps) {
    // 如果是 PanelContent 中渲染出来的该组件，那么共享 queryFields
    // 放在 UNSAFE_componentWillReceiveProps 生命周期中是因为父组件的 queryFields 是通过接口获取的
    if (this.props.childField && !isEqual(nextProps.queryFields, this.state.queryFields)) {
      this.setState({ queryFields: this.props.queryFields })
    }
  }

  getQueryFields = () => {
    const { code, formId, customConfigId, login, dispatch } = this.props
    const json = initFilter(login.OrgId, formId, '', 0, 1, customConfigId, login.userId, code)
    dispatch({
      type: 'search/getUserConfig',
      payload: json
    }).then(ret => {
      if (ret && ret.Nav_Fields) {
        this.setState({
          queryFields: ret.Nav_Fields.filter(item => !item.IsCustom)
        })
      }
    })
  }

  getGroupConfigs = (fields, groups, parentId, parent, list, fieldConfigs) => {
    const tempGroups = groups.filter(item => item.PARENT_ID === parentId)
    if (tempGroups && tempGroups.length) {
      tempGroups.sort((x, y) => x.NUM - y.NUM)
      tempGroups.forEach(group => {
        const config = {
          id: group.ID || guid(),
          title: group.TITLE,
          parentId: group.PARENT_ID,
          code: group.CODE,
          relationType: group.RELATION_TYPE,
          isDisplay: group.IS_DISPLAY,
          userCCQueryId: group.USER_C_C_QUERY_ID
        }
        const tempFields = fields.filter(item => item.USER_C_C_QUERY_GROUP_ID === config.id)
        if (tempFields && tempFields.length) {
          config.fieldConfigs = []
          tempFields.forEach(item => {
            const fieldConfig = getFieldConfigs({
              field: item,
              onPressEnter: this.onPressEnter,
              onChange: this.onChange
            })
            config.fieldConfigs.push(fieldConfig)
            fieldConfigs.push(fieldConfig)
          })
        }
        if (parent) {
          !parent.childGroups && (parent.childGroups = [])
          parent.childGroups.push(config)
        } else {
          list.push(config)
        }
        this.getGroupConfigs(fields, groups, config.id, config, list, fieldConfigs)
      })
    }
  }

  setGroupConfigs = ({ fields, groups, presetValue }) => {
    const fieldConfigs = []
    const groupConfigs = []
    if (groups && groups.length) {
      groups.sort((x, y) => x.NUM - y.NUM)
      this.getGroupConfigs(fields, groups, null, null, groupConfigs, fieldConfigs)
    }
    // 赋值 data { field: value }
    const data = {}
    fieldConfigs.forEach(item => {
      if (presetValue !== undefined && typeof presetValue === 'object' && Object.keys(presetValue).length) {
        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.setState({
      data,
      groupConfigs
    })
  }

  // 新增一组配置 提供给 ref 调用
  addGroupConfig = (id) => {
    const { code, customConfigId } = this.props
    const config = {
      id: guid(),
      parentId: id,
      relationType: 1,
      isDisplay: true,
      code,
      userCCQueryId: customConfigId || null
    }

    const find = digGroupData(this.state.groupConfigs, id)
    if (find) {
      !find.childGroups && (find.childGroups = [])
      find.childGroups.push(config)
    } else if (!id) {
      // 无 id，代表新增根配置
      this.state.groupConfigs.push(config)
    }
    // 直接修改 state，并使用 forceUpdate 更新，目的是为了保持对父组件 state 值的引用
    this.forceUpdate()
  }

  // 删除一组配置
  deleteGroupConfig = (id) => {
    const findIndex = this.state.groupConfigs.findIndex(item => item.id === id)
    if (findIndex !== -1) {
      this.state.groupConfigs.splice(findIndex, 1)
      // 直接修改 state，并使用 forceUpdate 更新，目的是为了保持对父组件 state 值的引用
      this.forceUpdate()
    }
  }

  // 分组关系选择
  onSelectChange = (id, value) => {
    const find = digGroupData(this.state.groupConfigs, id)
    if (find) {
      find.relationType = value
      // 直接修改 state，并使用 forceUpdate 更新，目的是为了保持对父组件 state 值的引用
      this.forceUpdate()
    }
  }

  // PanelContent 内容更新
  onPanelContentChange = () => {
    this.forceUpdate()
  }

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

  // field change 时候赋值给 data
  onChange = (params) => {
    const { value, colConfig } = params
    setDataFieldValue(this.state.data, colConfig.id, value)
    // 直接修改 state，并使用 forceUpdate 更新，目的是为了保持对父组件 state 值的引用
    this.forceUpdate()
  }

  /**
   * 执行搜索，搜索流程为：
   * 调用 Search 组件 onSearch 方法，
   * 然后 Search 分别通过 ref 分别调用 AdvanceSearch 和 SearchGroupField 的 getSearchParams 方法获取到搜索参数，
   * 最后再由 Search 组件完成搜索操作，这样搜索就统一在 Search 中做了
   */
  handleSearch = () => {
    const { onSearch } = this.props
    onSearch instanceof Function && onSearch()
  }

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

  render () {
    const { data, groupConfigs, queryFields } = this.state
    return (
      <IFComponent IF={groupConfigs.length}>
        <Collapse activeKey={groupConfigs.map(item => item.id)} className='opt-search__collapseWrap'>
          {
            groupConfigs.map((config, index) => {
              return (
                <Panel
                  header={
                    <CPanelHeader
                      config={config}
                      index={index}
                      onSelectChange={val => this.onSelectChange(config.id, val)}
                      deleteGroupConfig={() => this.deleteGroupConfig(config.id)}
                      addGroupConfig={() => this.addGroupConfig(config.id)}
                    />
                  }
                  key={config.id}
                  showArrow={false}
                  style={{ background: '#eee' }}
                >
                  <PanelContent
                    {...this.props}
                    data={data}
                    queryFields={queryFields}
                    config={config}
                    onPanelContentChange={this.onPanelContentChange}
                    onChange={this.onChange}
                    onPressEnter={this.onPressEnter}
                  />
                </Panel>
              )
            })
          }
        </Collapse>
      </IFComponent>
    )
  }
}

export default connect(({ login }) => ({ login }))(SearchGroupField)
