import React from 'react'
import newEventActions from 'actions/newEvent'
import treeStores from 'stores/tree'
import { getEventBlockByBid, emptyCon } from 'stores/funcs/newEvent'
import newEventStores from 'stores/newEvent'
import { cpJson, shallowEqualImmutable } from 'utils/utils'
import { BLOCK_OP_TYPE } from 'const/const'
import BlockEventConItem from './BlockConConItem'

export default class BlockConCons extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      cons: this.getCons()
    }

    this.onEventChange = this.onEventChange.bind(this)
    this.getCons = this.getCons.bind(this)
    this.changeConsAst = this.changeConsAst.bind(this)
    this.addBlockCon = this.addBlockCon.bind(this)
    this.delBlockCon = this.delBlockCon.bind(this)
  }

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

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

  componentWillUnmount() {
    this.unsubscribe()
  }

  componentDidUpdate(preProps) {
    if (preProps.bid !== this.props.bid) {
      this.setState({
        cons: this.getCons()
      })
    }
  }

  onEventChange(status) {
    let obj = {}
    if (status && status.types) {
      if (
        status.types.includes('updateBlockProp') &&
        this.props.bid === status.data.affectBlockId &&
        status.data.prop === 'cons'
      ) {
        // 这里需要强制更新, 因为cons是个对象
        this.forceUpdate()
      }
    }
    if (Object.keys(obj).length > 0) {
      this.setState(obj)
    }
  }

  genConItem({ obj, flag }) {
    let result = {}
    result['flag'] = flag
    result['operator'] = obj.op
    result['value1'] = obj.args[0].expVal
    result['value2'] = obj.args[1].expVal
    return result
  }

  getCons() {
    let result = []
    let nodeId = this.props.eventNodeId || treeStores.curEventNodeId
    let block = getEventBlockByBid(this.props.bid, nodeId)
    if (
      block &&
      (block.op === BLOCK_OP_TYPE.IF || block.op === BLOCK_OP_TYPE.ELSE)
    ) {
      let conObj = block.args[0]
      if (conObj && conObj.op) {
        switch (conObj.op) {
          case 'or':
            let orArgs = conObj.args
            orArgs.forEach(orItem => {
              if (orItem.op === 'and') {
                let andArgs = orItem.args
                andArgs.forEach((andItem, index) => {
                  let flag = index === 0 ? 'or' : 'and'
                  let con = this.genConItem({ obj: andItem, flag })
                  result.push(con)
                })
              } else {
                let con = this.genConItem({ obj: orItem, flag: 'or' })
                result.push(con)
              }
            })
            break
          case 'and':
            let andArgs = conObj.args
            andArgs.forEach(andItem => {
              let con = this.genConItem({ obj: andItem, flag: 'and' })
              result.push(con)
            })
            break
          default:
            let con = this.genConItem({ obj: conObj, flag: 'and' })
            result.push(con)
        }
      }
    }
    return result
  }

  genConObj(conItem) {
    let obj = {
      op: conItem.operator,
      args: [
        { op: 'var', expVal: conItem.value1, args: [] },
        { op: 'var', expVal: conItem.value2, args: [] }
      ]
    }
    return obj
  }

  changeConsAst() {
    // 将cons数组转为ast格式
    let cons = cpJson(this.state.cons)
    let ors = []
    let ands = []
    cons.forEach((con, index) => {
      if (con.flag !== 'or') {
        ands.push(con)
      } else {
        ors.push(ands)
        ands = []
        ands.push(con)
      }
      if (index === cons.length - 1) {
        ors.push(ands)
      }
    })

    let consAst = {}
    if (ors.length > 1) {
      // 有or
      consAst.op = 'or'
      consAst.args = []
      ors.forEach(orItem => {
        if (orItem.length > 1) {
          // 多个条件
          let andObj = {
            op: 'and',
            args: []
          }
          orItem.forEach(conItem => {
            let conObj = this.genConObj(conItem)
            andObj.args.push(conObj)
          })
          consAst.args.push(andObj)
        } else {
          // 单个条件
          let conObj = this.genConObj(orItem[0])
          consAst.args.push(conObj)
        }
      })
    } else {
      // 没有or
      consAst.op = 'and'
      consAst.args = []
      let andArray = ors[0]
      if (andArray.length > 1) {
        // 多个条件
        andArray.forEach(conItem => {
          let conObj = this.genConObj(conItem)
          consAst.args.push(conObj)
        })
      } else {
        // 单个条件
        consAst = this.genConObj(andArray[0])
      }
    }

    let nodeId = this.props.eventNodeId || treeStores.curEventNodeId
    newEventActions.updateBlockProp({
      nodeId,
      blockId: this.props.bid,
      prop: 'cons',
      value: consAst,
      trigger: true,
      addRecord: true
    })
  }

  addBlockCon() {
    let cons = this.state.cons
    let newEmptyCon = emptyCon()
    cons.push(newEmptyCon)
  }

  delBlockCon({ index, resetLast }) {
    let cons = this.state.cons
    if (resetLast && cons.length === 1) {
      cons[0] = emptyCon()
    } else {
      cons.splice(index, 1)
    }
    if (cons.length === 1) {
      cons[0].flag = 'and'
    }
  }

  render() {
    let cons = (
      <div className="con-items-wrap">
        {this.state.cons.map((con, index) => {
          return (
            <BlockEventConItem
              index={index}
              con={con}
              key={index}
              layer={this.props.layer}
              groupLayer={this.props.groupLayer}
              nestGroupLayer={this.props.nestGroupLayer}
              extraGapGroupLayer={this.props.extraGapGroupLayer}
              bid={this.props.bid}
              eventNodeId={this.props.eventNodeId}
              onConsChange={this.changeConsAst}
              onAddBlockCon={this.addBlockCon}
              onDelBlockCon={this.delBlockCon}
            />
          )
        })}
      </div>
    )

    return (
      <div className="con-cons flex-1">
        {!this.state.cons || this.state.cons.length === 0 ? null : cons}
      </div>
    )
  }
}
