import React from 'react'
import cls from 'classnames'
import newEventStores from 'stores/newEvent'
import { getEventBlockByBid } from 'stores/funcs/newEvent'
import { shallowEqualImmutable } from 'utils/utils'
import { EVENT_BLOCK_TYPE, BLOCK_OP_TYPE } from 'const/const'

export default class BlockChildren extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      subBlockIds: this.getBlockChildren(props.parentBid)
    }
    // 加载相关组件
    this.blockAction = require('../BlockAction').default
    this.blockCon = require('../BlockCon').default
    this.blockLoop = require('../BlockLoop').default
    this.blockComment = require('../BlockComment').default
    this.blockGroup = require('../BlockGroup').default
    // this.blockError = require('./BlockError').default

    this.onEventChange = this.onEventChange.bind(this)
    this.getBlockChildren = this.getBlockChildren.bind(this)
    this.getChild = this.getChild.bind(this)
    this.isBlockGroupChildren = this.isBlockGroupChildren.bind(this)
    this.getBlockGroupBg = this.getBlockGroupBg.bind(this)
  }

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

  componentDidUpdate(preProps) {
    // parentBid改变时需要更新
    if (preProps.parentBid !== this.props.parentBid) {
      let obj = {}
      let subBlockIds = this.getBlockChildren()
      if (!shallowEqualImmutable(this.state.subBlockIds, subBlockIds)) {
        obj.subBlockIds = subBlockIds
      }
      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 && status.types) {
      if (
        (status.types.includes('changeBlockChildren') &&
          status.data &&
          status.data.parentBid === this.props.parentBid) ||
        (status.types.includes('reloadBlock') &&
          this.props.parentBid === status.data.affectBlockId)
      ) {
        obj.subBlockIds = this.getBlockChildren()
      }
    }
    if (Object.keys(obj).length > 0) {
      this.setState(obj)
    }
  }

  getBlockChildren() {
    let childBids = []
    let nodeId = this.props.eventNodeId
    let parentBlock = getEventBlockByBid(this.props.parentBid, nodeId)
    if (parentBlock) {
      if (parentBlock.eventId) {
        if (
          parentBlock.ast &&
          parentBlock.ast.args &&
          parentBlock.ast.args.length > 0
        ) {
          parentBlock.ast.args.forEach(child => {
            if (child.ln) {
              childBids.push(child.ln)
            }
          })
        }
      } else {
        switch (parentBlock.op) {
          case BLOCK_OP_TYPE.IF:
          case BLOCK_OP_TYPE.ELSE:
          case BLOCK_OP_TYPE.FOR:
          case BLOCK_OP_TYPE.WHILE:
            if (
              parentBlock.args &&
              parentBlock.args.length > 0 &&
              parentBlock.args[1]
            ) {
              if (
                parentBlock.args[1].op === 'block' &&
                parentBlock.args[1].args &&
                parentBlock.args[1].args.length > 0
              ) {
                parentBlock.args[1].args.forEach(child => {
                  if (child.ln) {
                    childBids.push(child.ln)
                  }
                })
              }
            }
            break
          case BLOCK_OP_TYPE.BLOCK:
            if (parentBlock.args && parentBlock.args.length > 0) {
              parentBlock.args.forEach(child => {
                if (child.ln) {
                  childBids.push(child.ln)
                }
              })
            }
            break
        }
      }
    }
    return childBids
  }

  getChild(bid, index) {
    let nodeId = this.props.eventNodeId
    let block = getEventBlockByBid(bid, nodeId)
    if (block) {
      switch (block.op) {
        case BLOCK_OP_TYPE.SET:
        case BLOCK_OP_TYPE.CALL:
        case BLOCK_OP_TYPE.LET:
        case undefined:
          let BlockAction = this.blockAction
          return (
            <BlockAction
              key={index}
              layer={this.props.layer}
              groupLayer={this.props.groupLayer}
              nestGroupLayer={this.props.nestGroupLayer}
              offspringInNestGroupLayer={this.props.offspringInNestGroupLayer}
              extraGapGroupLayer={this.props.extraGapGroupLayer}
              loops={this.props.loops}
              bid={bid}
              eventNodeId={this.props.eventNodeId}
              visibleBlockIds={this.props.visibleBlockIds}
              isLast={index === this.state.subBlockIds.length - 1}
              virtualLayer={this.props.virtualLayer}
            />
          )
        case BLOCK_OP_TYPE.IF:
        case BLOCK_OP_TYPE.ELSE:
          let BlockCon = this.blockCon
          return (
            <BlockCon
              key={index}
              layer={this.props.layer}
              groupLayer={this.props.groupLayer}
              nestGroupLayer={this.props.nestGroupLayer}
              offspringInNestGroupLayer={this.props.offspringInNestGroupLayer}
              extraGapGroupLayer={this.props.extraGapGroupLayer}
              loops={this.props.loops}
              bid={bid}
              eventNodeId={this.props.eventNodeId}
              visibleBlockIds={this.props.visibleBlockIds}
              isLast={index === this.state.subBlockIds.length - 1}
              virtualLayer={this.props.virtualLayer}
            />
          )
        case BLOCK_OP_TYPE.FOR:
        case BLOCK_OP_TYPE.WHILE:
          let BlockLoop = this.blockLoop
          return (
            <BlockLoop
              key={index}
              layer={this.props.layer}
              groupLayer={this.props.groupLayer}
              nestGroupLayer={this.props.nestGroupLayer}
              offspringInNestGroupLayer={this.props.offspringInNestGroupLayer}
              extraGapGroupLayer={this.props.extraGapGroupLayer}
              loops={this.props.loops}
              bid={bid}
              eventNodeId={this.props.eventNodeId}
              visibleBlockIds={this.props.visibleBlockIds}
              isLast={index === this.state.subBlockIds.length - 1}
              virtualLayer={this.props.virtualLayer}
            />
          )
        case BLOCK_OP_TYPE.NOP:
          let BlockComment = this.blockComment
          return (
            <BlockComment
              key={index}
              layer={this.props.layer}
              groupLayer={this.props.groupLayer}
              nestGroupLayer={this.props.nestGroupLayer}
              offspringInNestGroupLayer={this.props.offspringInNestGroupLayer}
              extraGapGroupLayer={this.props.extraGapGroupLayer}
              loops={this.props.loops}
              bid={bid}
              eventNodeId={this.props.eventNodeId}
              visibleBlockIds={this.props.visibleBlockIds}
              isLast={index === this.state.subBlockIds.length - 1}
              virtualLayer={this.props.virtualLayer}
            />
          )
        case BLOCK_OP_TYPE.BLOCK:
          let BlockGroup = this.blockGroup
          //Group的嵌套处理
          return (
            <BlockGroup
              key={index}
              layer={this.props.layer}
              groupLayer={this.props.groupLayer}
              nestGroupLayer={this.props.nestGroupLayer}
              offspringInNestGroupLayer={this.props.offspringInNestGroupLayer}
              extraGapGroupLayer={this.props.extraGapGroupLayer}
              loops={this.props.loops}
              bid={bid}
              eventNodeId={this.props.eventNodeId}
              visibleBlockIds={this.props.visibleBlockIds}
              isLast={index === this.state.subBlockIds.length - 1}
              virtualLayer={this.props.virtualLayer}
            />
          )
      }
    } else {
      // let BlockError = this.blockError
      // return (
      //   <BlockError
      //     key={index}
      //     layer={this.props.layer}
      //     groupLayer={this.props.groupLayer}
      //     nestGroupLayer={this.props.nestGroupLayer}
      //     offspringInNestGroupLayer={this.props.offspringInNestGroupLayer}
      //     extraGapGroupLayer={this.props.extraGapGroupLayer}
      //     loops={this.props.loops}
      //     bid={bid}
      //     eventNodeId={this.props.eventNodeId}
      //     visibleBlockIds={this.props.visibleBlockIds}
      //     isLast={index === this.state.subBlockIds.length - 1}
      //     virtualLayer={this.props.virtualLayer}
      //   />
      // )
    }
    return null
  }

  isBlockGroupChildren = () => {
    let nodeId = this.props.eventNodeId
    let parentBlock = getEventBlockByBid(this.props.parentBid, nodeId)
    return parentBlock?.op === BLOCK_OP_TYPE.BLOCK
  }

  getBlockGroupBg = () => {
    const leftGap = 18 + (this.props.nestGroupLayer - 1) * 2
    const gapping = `${leftGap + (this.props.groupLayer - 1) * 2}px`
    const left = `${leftGap}px`
    const style = {
      width: `calc(100% - ${gapping})`,
      left: left
    }
    return this.isBlockGroupChildren() ? (
      <div className={'block-group-bg'} style={style} />
    ) : null
  }

  render() {
    let subBlockIds = this.state.subBlockIds
    if (this.props.visibleBlockIds) {
      subBlockIds = subBlockIds.filter(id => {
        return this.props.visibleBlockIds.indexOf(id) >= 0
      })
    }
    return subBlockIds && subBlockIds.length > 0 ? (
      <div
        className={cls('block-children', {
          'block-group-children': this.isBlockGroupChildren()
        })}
      >
        {this.getBlockGroupBg()}
        {subBlockIds.map((subBlockId, index) => {
          return this.getChild(subBlockId, index)
        })}
      </div>
    ) : null
  }
}
