import React from 'react'
import { shallowEqualImmutable, getY, isMac } from 'utils/utils'
import uiActions from 'actions/ui'
import newEventActions from 'actions/newEvent'
import newEventStores from 'stores/newEvent'
import {
  getEventBlockByBid,
  filterBlocks,
  getBidList
} from 'stores/funcs/newEvent'
import { dragPosition, dragUtils } from 'stores/funcs/event/dragUtils'
import { CONTEXT_MENU_TYPE, EVENT_BLOCK_TYPE, BLOCK_OP_TYPE } from 'const/const'

export default class Block extends React.Component {
  constructor(props) {
    super(props)
    this.curBlockId = newEventStores.curBlockId
    this.multiBlockIds = newEventStores.multiBlockIds
    this.state = {
      isActive: this.isActive(props.bid),
      isEnable: this.isEnable(props.bid),
      isExpand: this.isExpand(props.bid),
      hasChildren: this.hasChildren(props.bid)
    }
    this.onEventChange = this.onEventChange.bind(this)

    this.isActive = this.isActive.bind(this)
    this.isEnable = this.isEnable.bind(this)
    this.isExpand = this.isExpand.bind(this)

    this.onSelectBlock = this.onSelectBlock.bind(this)
    this.onToggleBlockExpand = this.onToggleBlockExpand.bind(this)

    this.getLineColor = this.getLineColor.bind(this)
    this.getGapLeft = this.getGapLeft.bind(this)

    // 拖拽
    this.allowDrag = this.allowDrag.bind(this)
    this.allowDrop = this.allowDrop.bind(this)
    this.getPosition = this.getPosition.bind(this)
    this.onDragStart = this.onDragStart.bind(this)
    this.onDragEnd = this.onDragEnd.bind(this)
    this.onDragOver = this.onDragOver.bind(this)
    this.onDrop = this.onDrop.bind(this)

    // 右键
    this.onContextMenu = this.onContextMenu.bind(this)
  }

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

  componentDidUpdate(preProps) {
    let obj = {}
    // bid改变时需要更新
    if (preProps.bid !== this.props.bid) {
      obj.isActive = this.isActive()
      obj.isEnable = this.isEnable()
      obj.isExpand = this.isExpand()
      obj.hasChildren = this.hasChildren()
    }
    if (Object.keys(obj).length > 0) {
      this.setState(obj)
    }
  }

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

  componentWillUnmount() {
    this.unsubscribe()
  }

  onEventChange(status) {
    let obj = {}
    if (status.types.includes('curBlockId')) {
      if (this.curBlockId !== status.data.curBlockId) {
        this.curBlockId = status.data.curBlockId
        let isActive = this.isActive()
        if (this.state.isActive !== isActive) {
          obj.isActive = isActive
        }
      }
    }
    if (status.types.includes('multiBlockIds')) {
      this.multiBlockIds = status.data.multiBlockIds
      let isActive = this.isActive()
      if (this.state.isActive !== isActive) {
        obj.isActive = isActive
      }
    }
    if (status.types.includes('toggleBlockProp')) {
      if (this.props.bid === status.data.affectBlockId) {
        if (status.data.prop === 'skip') {
          let isEnable = this.isEnable()
          if (this.state.isEnable !== isEnable) {
            obj.isEnable = isEnable
          }
        } else if (status.data.prop === 'expand') {
          let isExpand = this.isExpand()
          if (this.state.isExpand !== isExpand) {
            obj.isExpand = isExpand
          }
        }
      }
    }
    if (
      (status.types.includes('changeBlockChildren') &&
        status.data &&
        status.data.parentBid === this.props.bid) ||
      (status.types.includes('reloadBlock') &&
        this.props.bid === status.data.affectBlockId)
    ) {
      let hasChildren = this.hasChildren()
      if (hasChildren !== this.state.hasChildren) {
        obj.hasChildren = hasChildren
      }
    }
    if (Object.keys(obj).length > 0) {
      this.setState(obj)
    }
  }

  isActive(bid) {
    let _bid = bid || this.props.bid
    return this.curBlockId === _bid || this.multiBlockIds.indexOf(_bid) >= 0
  }

  isEnable(bid) {
    let _bid = bid || this.props.bid
    let nodeId = this.props.eventNodeId
    let result = true
    let block = getEventBlockByBid(_bid, nodeId)
    if (block) {
      result = !block.skip
    }
    return result
  }

  isExpand(bid) {
    let _bid = bid || this.props.bid
    let nodeId = this.props.eventNodeId
    let result = true
    let block = getEventBlockByBid(_bid, nodeId)
    if (block) {
      result = block.expand !== false
    }
    return result
  }

  hasChildren(bid) {
    let _bid = bid || this.props.bid
    let nodeId = this.props.eventNodeId
    let result = false
    let block = getEventBlockByBid(_bid, nodeId)
    if (block) {
      if (block.eventId) {
        result = block.ast && block.ast.args && block.ast.args.length > 0
      } else {
        switch (block.op) {
          case BLOCK_OP_TYPE.IF:
          case BLOCK_OP_TYPE.ELSE:
          case BLOCK_OP_TYPE.FOR:
          case BLOCK_OP_TYPE.WHILE:
            result =
              block.args &&
              block.args[1] &&
              block.args[1].args &&
              block.args[1].args.length > 0
            break
          case BLOCK_OP_TYPE.BLOCK:
            result = block.args && block.args.length > 0
            break
        }
      }
    }
    return result
  }

  onSelectBlock(e, allowMulti = false) {
    if (
      this.props.eventNodeId &&
      this.props.eventNodeId !== newEventStores.curEventNodeId
    ) {
      newEventActions.selectEvent({ eventNodeId: this.props.eventNodeId })
    } else {
      // 多选
      // let isCtrl = e && (isMac ? e.metaKey : e.ctrlKey)
      // if (isCtrl) {
      //   newEventActions.selectMultiBlocks({ blockId: this.props.bid })
      //   return
      // }
      // let isShift = e && e.shiftKey
      // if (isShift) {
      //   newEventActions.shiftSelectBlocks({ blockId: this.props.bid })
      //   return
      // }
    }
    if (
      !this.state.isActive ||
      (this.multiBlockIds.length > 0 &&
        (!allowMulti ||
          (allowMulti && !this.multiBlockIds?.includes(this.props.bid))))
    ) {
      newEventActions.selectBlock({ blockId: this.props.bid })
    }
  }

  onToggleBlockExpand() {
    newEventActions.toggleBlockProp({
      nodeId: this.props.eventNodeId,
      blockId: this.props.bid,
      prop: 'expand'
    })
  }

  getLineColor() {
    let group = ['red', 'green', 'purple', 'ching', 'orange', 'blue']
    return group[this.props.layer % 6]
  }

  getNextLineColor() {
    let group = ['red', 'green', 'purple', 'ching', 'orange', 'blue']
    return group[(this.props.layer + 1) % 6]
  }

  getGapLeft() {
    return 8 + this.props.layer * 20 + (this.props.layer + 1)
  }

  getGroupColor() {
    const group = ['color1', 'color2', 'color3', 'color4', 'color5']
    // const group = ['#7F438F', '#E5C88E', '#EEB2B2', '#B5D8F1', '#CBFF97']
    return group[this.props.groupLayer % 5]
  }

  blockMainStyle() {
    if (this.props.groupLayer >= 1) {
      return {
        paddingLeft: `${(this.props.nestGroupLayer - 1) * 2}px`,
        marginRight: `${this.props.groupLayer * 2}px`
      }
    }
    return null
  }

  getLoops(bid) {
    let _bid = bid || this.props.bid
    let nodeId = this.props.eventNodeId
    let block = getEventBlockByBid(_bid, nodeId)
    if (
      block &&
      (block.op === BLOCK_OP_TYPE.FOR || block.op === BLOCK_OP_TYPE.WHILE)
    ) {
      if (this.props.loops) {
        return JSON.stringify(
          [].concat(JSON.parse(this.props.loops), [block.ln])
        )
      } else {
        return JSON.stringify([block.ln])
      }
    } else {
      return this.props.loops
    }
  }

  indexLeftStyle() {
    if (
      this.props.offspringInNestGroupLayer >= 2 &&
      this.props.nestGroupLayer === 0
    ) {
      return {
        marginLeft: 20 + (this.props.offspringInNestGroupLayer - 1) * 2 + 'px'
      }
    }
    return undefined
  }

  extraGapGroupLayer() {
    if (
      this.props.offspringInNestGroupLayer >= 2 &&
      this.props.nestGroupLayer === 0
    ) {
      return this.props.offspringInNestGroupLayer
    } else {
      return this.props.extraGapGroupLayer || 0
    }
  }

  //拖拽
  allowDrag() {
    let allow = true
    if (
      document.activeElement.tagName === 'INPUT' ||
      document.activeElement.tagName === 'TEXTAREA'
    ) {
      allow = false // block dragging
    }
    if (!this.isActive(this.props.bid)) {
      this.onSelectBlock()
    }
    return allow
  }

  allowDrop(bid, position, multiInfo) {
    let result = false
    let nodeId = this.props.eventNodeId
    let dragBlock = getEventBlockByBid(bid, nodeId)
    let targetBlock = getEventBlockByBid(this.props.bid)
    let dropBlock = undefined
    switch (position) {
      case dragPosition.mid:
        // 加到targetBlock里面
        dropBlock = targetBlock
        break
      case dragPosition.bot:
      case dragPosition.top:
        // 实际是放在targetBlock的父级
        if (targetBlock.parentBid) {
          let targetParentBlock = getEventBlockByBid(
            targetBlock.parentBid,
            nodeId
          )
          if (targetParentBlock) {
            dropBlock = targetParentBlock
          } else {
            dropBlock = undefined
          }
        }
        break
    }
    if (multiInfo && multiInfo.length > 0) {
      // 多个移动
      let blockTypes = []
      multiInfo = filterBlocks(multiInfo)
      multiInfo.forEach(bid => {
        let block = getEventBlockByBid(bid, nodeId)
        if (block && block.type) {
          let type = block.type
          if (blockTypes.indexOf(type) === -1) {
            blockTypes.push(type)
          }
        }
      })
      if (
        targetBlock &&
        targetBlock.type === EVENT_BLOCK_TYPE.ROOT &&
        blockTypes.length === 1 &&
        blockTypes[0] === EVENT_BLOCK_TYPE.ROOT &&
        position !== dragPosition.mid
      ) {
        // 拖的和drop的都是Root只可放上和下
        result = true
      } else if (dropBlock) {
        // 提炼出可drop的情况
        if (dropBlock.type === EVENT_BLOCK_TYPE.ACTION) {
          if (
            blockTypes.length === 1 &&
            blockTypes[0] === EVENT_BLOCK_TYPE.STATUS &&
            dropBlock.action &&
            dropBlock.action.callback === true
          ) {
            result = true
          }
        } else if (dropBlock.type === EVENT_BLOCK_TYPE.COMMENT) {
          result = false
        } else {
          if (
            blockTypes.indexOf(EVENT_BLOCK_TYPE.ROOT) === -1 &&
            blockTypes.indexOf(EVENT_BLOCK_TYPE.STATUS) === -1
          ) {
            result = true
          }
        }
      }
    } else {
      // 单个移动
      if (
        dragBlock &&
        targetBlock &&
        dragBlock.type === EVENT_BLOCK_TYPE.ROOT &&
        targetBlock.type === EVENT_BLOCK_TYPE.ROOT &&
        position !== dragPosition.mid
      ) {
        // 拖的和drop的都是Root只可放上和下
        result = true
      } else if (dragBlock && dropBlock) {
        // 提炼出可drop的情况
        if (dropBlock.type === EVENT_BLOCK_TYPE.ACTION) {
          if (
            dragBlock.type === EVENT_BLOCK_TYPE.STATUS &&
            dropBlock.action &&
            dropBlock.action.callback === true
          ) {
            result = true
          }
        } else if (dropBlock.type === EVENT_BLOCK_TYPE.COMMENT) {
          result = false
        } else {
          if (
            dragBlock.type !== EVENT_BLOCK_TYPE.ROOT &&
            dragBlock.type !== EVENT_BLOCK_TYPE.STATUS
          ) {
            result = true
          }
        }
      }
    }
    return result
  }

  getPosition(dragBlockId, deltaTop, maxHeight, multiInfo) {
    let position = dragPosition.mid
    let mid1 = maxHeight / 3
    let mid2 = (maxHeight * 2) / 3
    if (deltaTop >= 0 && deltaTop <= mid1) {
      position = dragPosition.top
    } else if (deltaTop >= mid2 && deltaTop <= maxHeight) {
      position = dragPosition.bot
    }
    let nodeId = this.props.eventNodeId
    let dropBlock = getEventBlockByBid(this.props.bid, nodeId)
    if (multiInfo && multiInfo.length > 0) {
      // 多个移动
      let blockTypes = []
      multiInfo = filterBlocks(multiInfo)
      multiInfo.forEach(bid => {
        let block = getEventBlockByBid(bid, nodeId)
        if (block && block.type) {
          blockTypes.push(block.type)
        }
      })
      if (
        dropBlock &&
        dropBlock.type === EVENT_BLOCK_TYPE.ROOT &&
        blockTypes.indexOf(EVENT_BLOCK_TYPE.ROOT) === -1
      ) {
        // drop为root且drap均非root的情况
        position = dragPosition.mid
      }
    } else {
      // 单个移动
      let dragBlock = getEventBlockByBid(dragBlockId, nodeId)
      if (
        dropBlock &&
        dropBlock.type === EVENT_BLOCK_TYPE.ROOT &&
        !(dragBlock && dragBlock.type === EVENT_BLOCK_TYPE.ROOT)
      ) {
        // 不同为root的情况且drop的root的情况
        position = dragPosition.mid
      }
    }
    return position
  }

  onDragStart(e) {
    dragUtils.isDragging = true
    e.stopPropagation()
    if (!this.allowDrag()) {
      e.preventDefault()
      return
    }
    e.dataTransfer.effectAllowed = 'move'
    dragUtils.setDraggingItemInfo(this.props.bid, this.state.isExpand)
    dragUtils.setDraggingMultiItemsInfo(this.multiBlockIds)
    // 对block的处理
    if (this.multiBlockIds.length === 0) {
      if (this.state.isExpand && this.state.hasChildren) {
        // 关闭起来
        newEventActions.toggleBlockProp({
          nodeId: this.props.eventNodeId,
          blockId: this.props.bid,
          prop: 'expand',
          value: false,
          addRecord: false
        })
      }
    }
  }

  onDragEnd(e) {
    // drop先执行
    e.stopPropagation()
    if (dragUtils.isDragging) {
      dragUtils.isDragging = false
      let dragInfo = dragUtils.getDraggingItemInfo()
      // 对block的处理
      if (dragInfo) {
        newEventActions.toggleBlockProp({
          nodeId: this.props.eventNodeId,
          blockId: dragInfo.bid,
          prop: 'expand',
          value: dragInfo.expand,
          addRecord: false
        })
      }
      dragUtils.resetDraggingItem()
    }
  }

  onDragOver(e) {
    e.stopPropagation()
    if (!dragUtils.isDragging) {
      return
    }
    e.preventDefault()
    let allowDrop = true
    let deltaTop =
      e.clientY -
      getY(e.currentTarget) +
      document.querySelector('.jenga-panel').scrollTop
    let maxHeight = e.currentTarget.clientHeight
    let position = dragPosition.mid
    let info = dragUtils.getDraggingItemInfo()
    let multiInfo = dragUtils.getDraggingMultiItemsInfo()
    if (multiInfo && multiInfo.length > 0) {
      // 多个移动
      // console.log('多个移动。。。')
      multiInfo = filterBlocks(multiInfo)
      let bidList = []
      multiInfo.forEach(bid => {
        getBidList({ blockId: bid, list: bidList })
      })
      if (bidList.indexOf(this.props.bid) > -1) {
        // dragOver为自己或childern时不允许
        allowDrop = false
        // console.log('包含自己。。。')
      } else {
        let blockTypes = []
        let nodeId = this.props.eventNodeId
        multiInfo.forEach(bid => {
          let block = getEventBlockByBid(bid, nodeId)
          if (block && block.type) {
            let type = block.type
            if (blockTypes.indexOf(type) === -1) {
              blockTypes.push(type)
            }
          }
        })
        if (
          multiInfo.length > 1 &&
          blockTypes.indexOf(EVENT_BLOCK_TYPE.ROOT) > -1 &&
          blockTypes.length > 1
        ) {
          // 多个待移动block中同时有root和非root时不允许
          allowDrop = false
          // console.log('同时有root和非root。。。')
        } else {
          // 对drag的处理
          // console.log('ok。。。')
          position = this.getPosition(info.bid, deltaTop, maxHeight, multiInfo)
          allowDrop = this.allowDrop(info.bid, position, multiInfo)
        }
      }
    } else {
      // 单个移动
      // console.log('单个移动。。。')
      // 相同bid不允许
      if (this.props.bid !== info.bid) {
        // 对drag的处理
        position = this.getPosition(info.bid, deltaTop, maxHeight, multiInfo)
        allowDrop = this.allowDrop(info.bid, position, multiInfo)
      } else {
        allowDrop = false
      }
    }
    dragUtils.setOverItemInfo(position, this.props.bid, allowDrop)
  }

  onDrop(e) {
    e.stopPropagation()
    e.preventDefault()
    dragUtils.isDragging = false
    let dragInfo = dragUtils.getDraggingItemInfo()
    let multiInfo = dragUtils.getDraggingMultiItemsInfo()
    multiInfo = filterBlocks(multiInfo)
    let overInfo = dragUtils.getOverItemInfo()
    // 对block的处理
    if (multiInfo.length === 0) {
      if (dragInfo) {
        newEventActions.toggleBlockProp({
          nodeId: this.props.eventNodeId,
          blockId: dragInfo.bid,
          prop: 'expand',
          value: dragInfo.expand,
          addRecord: false
        })
      }
    }
    // 移动block
    if (overInfo && overInfo.isAllow) {
      newEventActions.moveBlock({
        srcBlockId: dragInfo.bid,
        targetBlockId: overInfo.bid,
        position: overInfo.overPosition,
        multiSrcBlockIds: multiInfo
      })
    }
    dragUtils.resetDraggingItem()
  }

  onContextMenu(e) {
    e.preventDefault()
    e.stopPropagation()
    this.onSelectBlock(e, true)
    let info = {
      x: e.pageX,
      y: e.pageY,
      type: CONTEXT_MENU_TYPE.EVENT
    }
    uiActions.contextMenu(info)
  }

  render() {
    return null
  }
}
