// 核心库
import React from 'react'
import { connect } from 'dva/index'
// 组件库
import { TreeSelect, message } from 'antd'
// 工具库
import {
  extendInclude,
  extendOrder,
  extendRule,
  getDataFieldValue,
  initFilter,
  getParseValue,
  constructStandardTreeData
} from '../utils/common'
import { cloneDeep, get, isEqual } from 'lodash'

class TreeSelectInput extends React.Component {
  constructor (props) {
    super(props)
    this.state = {
      treeData: []
    }
  }

  componentDidMount () {
    this.loadData()
  }

  componentDidUpdate (prevProps, prevState) {
    if (!isEqual(prevState.treeData, this.state.treeData)) {
      const { data, onLoadData } = this.props
      onLoadData instanceof Function && onLoadData(data.id, this.state.treeData)
    }
  }

  /**
   * 根据下拉显示字段 配置
   * @param {*} opt
   */
  getLabelByShowField = opt => {
    const { data } = this.props
    const { showField } = data || {}
    const arrShowField = showField ? showField.split(',') : ['NAME']
    const nodearr = arrShowField.map((i, key) => {
      if (key < arrShowField.length && key > 0) {
        const v1 = getDataFieldValue(opt, i)
        return '-' + (v1 == null ? '空' : v1)
      } else {
        const v1 = getDataFieldValue(opt, i)
        return (v1 == null ? '空' : v1)
      }
    })
    return nodearr
  }

  /**
   * 获取接口参数
   * @param {*} value
   */
  getPramas = (value) => {
    const { app, login, data, record, colConfig, thisRef } = this.props
    const { sortField, showField, sortOrder, navField, extIncludeFields, showLevel } = data || {}
    const loadParam = initFilter(login.OrgId, '', '', 0)
    loadParam['Level'] = value ? 1 : (showLevel || 0)
    loadParam['MenuParameter'] = app.currActivatedMenu && app.currActivatedMenu.MENU_FORM_PARAMS ? app.currActivatedMenu.MENU_FORM_PARAMS : ''
    // 构建 FilterGroup.Rules 传参
    value && extendRule(loadParam, 'PARENT_ID', 1, value)
    if (colConfig && colConfig.column && colConfig.column.Nav_Filters && colConfig.column.Nav_Filters.length) {
      colConfig.column.Nav_Filters.forEach(t => {
        const v = getParseValue(
          t.VALUE,
          login.user,
          field => thisRef.getFieldValue(field, thisRef),
          field => getDataFieldValue(record, field)
        )
        if (v !== null && v !== undefined) {
          if (t.IS_CUSTOM) {
            loadParam[t.FIELD_NAME] = v
          } else {
            extendRule(loadParam, t.FIELD_NAME, t.OPERATION, v, t.IS_SYS_PARAM)
          }
        }
      })
    }

    // 添加自定义排序
    const sortFields = sortField ? sortField.split(',') : []
    const sortOrders = sortOrder ? sortOrder.split(',') : []
    if (sortFields && sortFields.length && sortOrders && sortOrders.length) {
      loadParam['Sort'] = ''
      sortFields.forEach((n, i) => {
        extendOrder(loadParam, n, sortOrders[i])
      })
    }
    // 添加导航属性
    const navFields = []
    const tmpNavFields = navField ? navField.split(',') : ['ID']
    if (tmpNavFields && tmpNavFields.length > 0) {
      tmpNavFields.forEach(t => {
        if (t && t.indexOf('.') > 0) {
          const pos = t.lastIndexOf('.')
          const includeField = t.substring(0, pos)
          navFields.push(includeField)
        }
      })
    }
    const arrShowField = showField ? showField.split(',') : ['CODE', 'NAME']
    if (arrShowField && arrShowField.length > 0) {
      arrShowField.forEach(t => {
        if (t && t.indexOf('.') > 0) {
          const pos = t.lastIndexOf('.')
          const includeField = t.substring(0, pos)
          navFields.push(includeField)
        }
      })
    }
    // 填充导航属性
    extIncludeFields && extIncludeFields.forEach(t => {
      navFields.push(t)
    })
    // 去重添加
    if (navFields.length) {
      const tmp = [...new Set(navFields)]
      tmp.forEach((n, i) => {
        extendInclude(loadParam, n)
      })
    }
    return loadParam
  }

  /**
   * 获取树数据
   * @param {*} selectedOptions
   */
  loadData = (treeNode = {}) => {
    const { api: url, data, value, dispatch } = this.props
    if (!url) return

    const targetOption = treeNode.props || {}
    return dispatch({
      type: 'app/getTableData',
      payload: this.getPramas(targetOption.id),
      url,
      onComplete: (ret) => {
        if (ret && ret.IsSuccessful && ret.Data) {
          const { showLevel, onlyLeaf, multipleChoice, selectCondition } = data
          // 一次性加载全部数据
          if (showLevel === -1) {
            constructStandardTreeData(ret.Data)
            this.setState({ treeData: ret.Data })
            return
          }
          // 判断是否需要更新选中的value，因为动态加载数据的树，父节点先勾选上后，展开子节点，这时候子节点会自动勾选上
          const needUpdateValue = multipleChoice && !onlyLeaf && targetOption.checked
          const updateValue = value ? value.split(',').filter(val => val !== targetOption.id) : []
          // 新数据源
          const treeData = cloneDeep(this.state.treeData)
          ret.Data.forEach(item => {
            const pId = targetOption.id
            const pLevel = targetOption.Level || 0
            const isLeaf = item.IsLeaf || !!(showLevel && showLevel >= 0 && (pLevel + 1 >= showLevel))
            // 判断树节点是否可选中
            const conditionSelectable = this.checkNodeSelectable(item, selectCondition)
            const disabled = !conditionSelectable || (onlyLeaf && !isLeaf)
            // 构建树数据源
            const dataSource = {
              id: item.Node.ID,
              pId,
              value: item.Node.ID,
              title: this.getLabelByShowField(item.Node),
              isLeaf,
              disabled,
              Level: pLevel + 1,
              Node: item.Node
            }
            treeData.push(dataSource)
            // 构建需要更新的 value 值
            updateValue.push(item.Node.ID)
          })
          // 如果继续加载发现该节点没有子节点了，那么这个节点就设置为子节点
          if (!ret.Data.length && !targetOption.isLeaf) {
            const findNode = treeData.find(item => item.id === targetOption.id)
            if (findNode) {
              findNode.isLeaf = true
              findNode.disabled = false
            }
          }
          // 更新树数据源
          this.setState({ treeData }, () => {
            needUpdateValue && this.onChange(updateValue)
          })
        } else {
          ret && message.error(ret.ErrorMessage)
        }
      }
    })
  }

  checkNodeSelectable = (node, condition) => {
    // condition: 'FIELD,OPERATE,VALUE'
    if (condition) {
      const configs = []
      const codes = condition.split('|')
      codes.forEach(code => {
        const splitArr = code.split(',')
        configs.push({
          field: splitArr[0],
          operate: Number(splitArr[1]),
          value: splitArr[2]
        })
      })
      return configs.find(conf => {
        let matchResult = false
        const { field, operate, value } = conf
        if (field) {
          const fieldValue = get(node, field)
          switch (operate) {
            case 1:
              matchResult = fieldValue == value
              break
            default:
              break
          }
        }
        return matchResult
      })
    }
    return true
  }

  onChange = (value, label, extra) => {
    const { triggerNode } = extra || {}
    if (value === undefined || (Array.isArray(value) && !value.length)) {
      this.updateValue(null)
      return
    }
    const { multipleChoice, checkStrictly } = this.props.data
    checkStrictly && (value = value.map(val => val.value))
    if (multipleChoice) {
      // 多选
      this.updateValue(value.join(','))
    } else {
      // 单选
      this.updateValue(value, triggerNode ? triggerNode.props.Node : undefined)
    }
  }

  updateValue = (value, record) => {
    const { onSelect, onChange, data, colConfig, thisRef } = this.props
    if (typeof onSelect === 'function') {
      const { navField } = data || {}
      const navFields = navField ? navField.split(',') : ['ID']
      const saveValues = []
      for (let j = 0; j < navFields.length; j++) {
        saveValues.push(getDataFieldValue(record, navFields[j]))
      }
      onSelect({
        data: saveValues,
        record,
        colConfig,
        thisRef
      })
    } else if (typeof onChange === 'function') {
      onChange({
        value,
        colConfig,
        thisRef
      })
    }
  }

  checkLabelInValue = (treeData, target) => {
    for (let i = 0, j = treeData.length; i < j; i++) {
      const data = treeData[i]
      if (data.value === target) {
        return data.title || data.label
      }
      if (Array.isArray(data.children) && data.children.length) {
        const result = this.checkLabelInValue(data.children, target)
        if (result) return result
      }
    }
  }

  getLabelInValue = () => {
    const { data, value } = this.props
    const { treeData } = this.state
    if (value) {
      const values = value.split(',')
      if (data.checkStrictly) {
        return values.map(val => {
          return {
            label: this.checkLabelInValue(treeData, val),
            value: val
          }
        })
      }
      return values
    }
    return undefined
  }

  render () {
    const { data, colConfig } = this.props
    const { multipleChoice: treeCheckable, checkStrictly: treeCheckStrictly, maxTagCount = 2, showLevel = 0 } = data
    const { disabled, promptInfo: placeholder } = colConfig
    const { treeData } = this.state
    const showValue = this.getLabelInValue()
    return (
      <TreeSelect
        allowClear
        treeCheckStrictly={treeCheckStrictly}
        treeDataSimpleMode={showLevel !== -1}
        placeholder={placeholder || `请选择${colConfig.label}`}
        disabled={disabled}
        maxTagCount={maxTagCount}
        treeCheckable={treeCheckable}
        value={showValue}
        treeData={treeData}
        loadData={showLevel !== -1 ? this.loadData : null}
        onChange={this.onChange}
        dropdownStyle={{ maxHeight: 480, overflow: 'auto' }}
      />
    )
  }
}

export default connect(({ app, login }) => ({ app, login }))(TreeSelectInput)
