import React from 'react'
import cls from 'classnames'
import i18n from 'i18next'
import { Menu, Dropdown } from 'antd'
import newEventActions from 'actions/newEvent'
import treeActions from 'actions/tree'
import newEventStores from 'stores/newEvent'
import widgetStore from 'stores/widget'
import treeStores from 'stores/tree'
import { shallowEqualImmutable } from 'utils/utils'
import getTypeIcon from 'utils/commons/getTypeIcon'
import {
  getEventBlockByBid,
  getParentBlock,
  getChildIndex,
  getEventNodeById,
  getActionBlockObjNode,
  getBlockObj
} from 'stores/funcs/newEvent'
import {
  nodeIsFunctionGroup,
  nodeIsService,
  nodeIsTransaction,
  nodeIsIotMessage,
  nodeIsDyTransaction,
  nodeIsFunction
} from 'stores/funcs/nodeType'
import { getNodeIconByEnvs } from 'stores/funcs/tree'
import {
  isServerRootNode,
  isChangedActionValid
} from 'stores/funcs/event/methodUtils'
import { getNodeTypeName, getFakeNodeIds } from 'stores/funcs/event/fakeNode'
import { EVENT_BLOCK_TYPE, BLOCK_OP_TYPE } from 'const/const'
import { specialActionObj, fakeNodeIds } from 'const/enum'
import BlockEnable from '../BlockEnable'
import ObjSelector from 'src/components/common/objSelector/ObjSelector'
import TitleTip from 'src/components/common/titleTip/TitleTip'

const MenuItem = Menu.Item

export default class BlockActionObject extends React.Component {
  constructor(props) {
    super(props)
    this.curEventNodeId = newEventStores.curEventNodeId
    this.state = {
      object: this.getObject()
    }
    this.objSelector = React.createRef()

    this.onEventChange = this.onEventChange.bind(this)
    this.genObjSelectConfig = this.genObjSelectConfig.bind(this)

    this.onAddAction = this.onAddAction.bind(this)

    this.shouldClearAction = this.shouldClearAction.bind(this)
    this.dealChangeActionObject = this.dealChangeActionObject.bind(this)
    this.onSelectObj = this.onSelectObj.bind(this)
    this.onActionObjectSelect = this.onActionObjectSelect.bind(this)

    this.getSpecialObjName = this.getSpecialObjName.bind(this)
    this.getActionObjName = this.getActionObjName.bind(this)
    this.getActionObjIcon = this.getActionObjIcon.bind(this)
    this.getObject = this.getObject.bind(this)

    this.jumpToNode = this.jumpToNode.bind(this)
    this.objJumpBtn = this.objJumpBtn.bind(this)
  }

  shouldComponentUpdate(nextProps, nextState) {
    return (
      !shallowEqualImmutable(this.props, nextProps) ||
      !shallowEqualImmutable(this.state, nextState)
    )
  }

  componentDidUpdate(preProps) {
    if (preProps.bid !== this.props.bid) {
      this.setState({
        object: this.getObject()
      })
    }
  }

  componentDidMount() {
    this.unsubscribe = newEventStores.listen(this.onEventChange)
  }

  componentWillUnmount() {
    this.unsubscribe()
  }

  onEventChange(status) {
    let obj = {}
    if (status) {
      if (
        status.types.includes('curEventNodeId') &&
        this.curEventNodeId !== status.data.curEventNodeId
      ) {
        this.curEventNodeId = status.data.curEventNodeId
      }
      if (
        status.types.includes('reloadBlock') &&
        this.props.bid === status.data.affectBlockId
      ) {
        obj.object = this.getObject()
      }
    }
    if (Object.keys(obj).length > 0) {
      this.setState(obj)
    }
  }

  genObjSelectConfig() {
    return {
      srcId: this.curEventNodeId,
      srcInStage: {
        stage: true,
        server: {
          allow: [
            'service',
            'db',
            'data-live',
            'data-excel',
            'data-sharedService'
          ],
          forbidden: [
            'data-mallProduct',
            'data-mallOrder',
            'data-mallCart',
            'data-voteCandidate',
            'data-voteRecord',
            'data-dynamoDb',
            'data-cacheDb',
            'data-email',
            'data-sms'
          ]
        }
      },
      srcInServer: {
        stage: false,
        server: true
      },
      srcFrom: 'actionObj'
    }
  }

  onAddAction() {
    let nodeId = this.props.eventNodeId || this.curEventNodeId
    let parentBlock = getParentBlock(this.props.bid, nodeId)
    if (parentBlock) {
      let index = getChildIndex(parentBlock, this.props.bid)
      if (index !== -1) {
        newEventActions.addBlock({
          type: EVENT_BLOCK_TYPE.ACTION,
          parentBid: parentBlock.eventId ? parentBlock.eventId : parentBlock.ln,
          index: index + 1
        })
      }
    }
  }

  shouldClearAction(block, obj) {
    let result = false
    let nodeId = this.props.eventNodeId || this.curEventNodeId
    let node = getEventNodeById(nodeId)
    // 对象改变
    let preObj = getBlockObj({ block })
    let preObject = getActionBlockObjNode({
      obj: preObj,
      nodeId
    })
    let curObject = getActionBlockObjNode({
      obj: obj,
      nodeId
    })
    if (
      (!preObject && curObject) ||
      (preObject && !curObject) ||
      (!preObject && !curObject && block.op) ||
      (preObject && curObject && preObject.type !== curObject.type)
    ) {
      result = true
    }
    // 处理服务为当前对象，且动作为设置返回结果的情况下，选择其他服务时，需要clear
    let actionName
    if (block.op === BLOCK_OP_TYPE.CALL) {
      if (block.val && Array.isArray(block.val)) {
        actionName = block.val[1]
      }
    }
    if (
      !result &&
      !isChangedActionValid({
        rootNode: node,
        blockNode: curObject,
        blockObj: obj,
        actionName
      })
    ) {
      result = true
    }
    return result
  }

  dealChangeActionObject(block, obj) {
    if (
      block &&
      (block.op === BLOCK_OP_TYPE.SET ||
        block.op === BLOCK_OP_TYPE.CALL ||
        block.op === BLOCK_OP_TYPE.LET ||
        block.op === undefined)
    ) {
      if (this.shouldClearAction(block, obj)) {
        block.op = undefined
        block.val = ''
        block.args = []
      }
    }
  }

  onSelectObj(obj) {
    let nodeId = this.props.eventNodeId || this.curEventNodeId
    let curBlock = getEventBlockByBid(this.props.bid, nodeId)
    if (curBlock) {
      this.dealChangeActionObject(curBlock, obj)
      this.setState(
        {
          object: obj
        },
        () => {
          newEventActions.updateBlockProp({
            nodeId,
            blockId: this.props.bid,
            prop: 'object',
            value: obj,
            trigger: true
          })
          // 更新部分obj的参数
          let node = getActionBlockObjNode({ obj, nodeId })
          newEventStores.reloadAction(node && node.id)
        }
      )
    }
  }

  onActionObjectSelect(option) {
    if (option) {
      if (option.key === 'objSelector') {
        this.objSelector && this.objSelector.current.componentNode.click()
      } else {
        this.onSelectObj(option.key)
      }
    }
  }

  getSpecialObjName(obj) {
    let name = obj
    switch (obj) {
      case 'curObj':
        let nodeId = this.props.eventNodeId || this.curEventNodeId
        let node = getEventNodeById(nodeId)
        if (node) {
          if (nodeIsService(node.type)) {
            if (nodeIsTransaction(node.type)) {
              name = i18n.t('EventView.jenga_action_block.curTransaction')
            } else if (nodeIsIotMessage(node.type)) {
              name = i18n.t('EventView.jenga_action_block.curIot')
            } else {
              name = i18n.t('EventView.jenga_action_block.curService')
            }
          } else if (nodeIsFunctionGroup(node.type)) {
            name = i18n.t('EventView.jenga_action_block.curAction')
          } else {
            name = i18n.t('EventView.jenga_action_block.curObject')
          }
        }
        break
      default:
        name = i18n.t('EventView.jenga_action_block.' + obj)
    }
    return name
  }

  getActionObjName(obj) {
    if (obj === 'objSelector') {
      return i18n.t('EventView.jenga_action_block.objSelector')
    } else {
      // 特殊且合法的对象
      if (specialActionObj.indexOf(obj) >= 0) {
        return this.actionObjList.indexOf(obj) >= 0
          ? this.getSpecialObjName(obj)
          : ''
      } else if (fakeNodeIds.indexOf(obj) >= 0) {
        return getNodeTypeName(obj)
      } else {
        let _obj = getEventNodeById(obj)
        return _obj ? _obj.uis.name || _obj.type : ''
      }
    }
  }

  getActionObjIcon(obj) {
    let nodeId = this.props.eventNodeId || this.curEventNodeId
    let node = getActionBlockObjNode({ obj, nodeId })
    let icon = null
    let type = 'map'
    if (node) {
      if (node && node.type && widgetStore.widget[node.type]) {
        icon = getNodeIconByEnvs(
          node.type,
          widgetStore.widget[node.type].icon,
          node.envs
        )
        type = 'icon'
      }
      if (!icon) {
        icon = getTypeIcon(node, treeStores.curCaseType)
        type = 'map'
      }
    }
    return { icon, type }
  }

  getObject() {
    let _obj
    let nodeId = this.props.eventNodeId || this.curEventNodeId
    let curBlock = getEventBlockByBid(this.props.bid, nodeId)
    if (curBlock) {
      _obj = getBlockObj({ block: curBlock })
    }
    return _obj
  }

  get actionObjList() {
    let curNode = getEventNodeById(this.state.curEventNodeId)
    if (nodeIsDyTransaction(curNode && curNode.type)) {
      // dy事务无相关选项
      return []
    }
    // 只有当前对象
    return specialActionObj.slice(0, 1)
  }

  get fakeNodes() {
    let fakeNodeIds = getFakeNodeIds() || []
    if (isServerRootNode(getEventNodeById(this.state.curEventNodeId))) {
      // 后台的伪对象
      fakeNodeIds = fakeNodeIds.filter(nodeId => {
        return nodeId === '$sobj_serverSys'
      })
    } else {
      // 前台的伪对象
      fakeNodeIds = fakeNodeIds.filter(nodeId => {
        return nodeId !== '$sobj_serverSys'
      })
    }
    return fakeNodeIds
  }

  jumpToNode(e) {
    e && e.stopPropagation()
    let nodeId = this.props.eventNodeId || this.curEventNodeId
    let node = getActionBlockObjNode({
      obj: this.state.object,
      nodeId
    })
    if (node && this.state.object !== 'curObj') {
      if (nodeIsFunctionGroup(node.type) || nodeIsService(node.type)) {
        newEventActions.toggleEventView({
          show: true,
          nodeId: node.id,
          mode: 'jenga'
        })
      } else {
        if (newEventStores.showEventView) {
          newEventActions.toggleEventView({ show: false })
        }
      }
      treeActions.selectNode(node.id)
      // if (nodeIsFunction(node.type)) {
      //   newEventActions.addNavId(node)
      // }
    }
  }

  objJumpBtn() {
    let obj = this.state.object
    if (obj !== 'curObj' && fakeNodeIds.indexOf(obj) === -1) {
      let node = getActionBlockObjNode({
        obj
      })
      if (
        node &&
        (nodeIsFunctionGroup(node.type) ||
          nodeIsService(node.type) ||
          nodeIsFunction(node.type))
      ) {
        return (
          <button className="btn-clear btn-jump" onClick={this.jumpToNode} />
        )
      }
    }
    return null
  }

  render() {
    let actionObjIconInfo = this.getActionObjIcon(this.state.object)
    let actionObjMenu = () => {
      let fakeNodes = this.fakeNodes
      return (
        <Menu
          className="object-select-menu"
          onClick={this.onActionObjectSelect}
        >
          <MenuItem key={'objSelector'}>
            {this.getActionObjName('objSelector')}
          </MenuItem>
          <Menu.Divider />
          {this.actionObjList.map(obj => {
            return <MenuItem key={obj}>{this.getActionObjName(obj)}</MenuItem>
          })}
          {fakeNodes && fakeNodes.length > 0 ? <Menu.Divider /> : null}
          {!fakeNodes || fakeNodes.length === 0
            ? null
            : fakeNodes.map(node => {
                return (
                  <MenuItem key={node} className={'fake-node'}>
                    {this.getActionObjName(node)}
                  </MenuItem>
                )
              })}
        </Menu>
      )
    }

    return (
      <div className="action-object f--h">
        <BlockEnable
          bid={this.props.bid}
          isEnable={this.props.isEnable}
          eventNodeId={this.props.eventNodeId}
        />
        <div className="object-wrap">
          <div className="select-wrap f--hlc">
            <Dropdown
              trigger={['click']}
              getPopupContainer={triggerNode => triggerNode.parentNode}
              overlayClassName={'object-select-dropdown'}
              overlay={actionObjMenu()}
            >
              <div className="object-select f--hlc">
                <ObjSelector
                  ref={this.objSelector}
                  stopPropagation={true}
                  config={this.genObjSelectConfig()}
                  cb={this.onSelectObj}
                />
                {actionObjIconInfo.type === 'icon' ? (
                  <div
                    className="icon-svg f--hcc"
                    dangerouslySetInnerHTML={{
                      __html: actionObjIconInfo.icon
                    }}
                  />
                ) : actionObjIconInfo.icon ? (
                  <div className={cls('icon-type', actionObjIconInfo.icon)} />
                ) : null}
                <TitleTip nodeId={this.state.object} maxLength={4}>
                  <input
                    value={this.getActionObjName(this.state.object)}
                    readOnly={true}
                    className={cls('ant-dropdown-input', {
                      'fake-node': fakeNodeIds.indexOf(this.state.object) >= 0
                    })}
                    placeholder={i18n.t(
                      'EventView.jenga_action_block.selectObject'
                    )}
                  />
                </TitleTip>
                {this.objJumpBtn()}
                <div className="ant-dropdown-icon" />
              </div>
            </Dropdown>
          </div>
          <div className="add-action-block-wrap f--hcc">
            <button
              className="btn-clear btn-add-action-block"
              onClick={this.onAddAction}
            >
              <div className="icon">
                <span className="horizon" />
                <span className="vertical" />
              </div>
            </button>
          </div>
        </div>
      </div>
    )
  }
}
