// Learn TypeScript:
//  - https://docs.cocos.com/creator/2.4/manual/en/scripting/typescript.html
// Learn Attribute:
//  - https://docs.cocos.com/creator/2.4/manual/en/scripting/reference/attributes.html
// Learn life-cycle callbacks:
//  - https://docs.cocos.com/creator/2.4/manual/en/scripting/life-cycle-callbacks.html

import { BLOCK_STATE, Config } from "./Config/GameConfig";
import propPool from "./propPool";
import { waitTime } from "./utils";

const { ccclass, property } = cc._decorator;

@ccclass
export default class BlockManager extends cc.Component {

  isMove = false

  viewWidth = 0

  viewHeight = 0

  /** 方块矩阵外层容器 */
  blockMatrix: cc.Node = null

  /** 默认位置 */
  defaultPos: cc.Vec2 = null

  start() {
    this.viewHeight = cc.view.getVisibleSize().height
    this.viewWidth = cc.view.getVisibleSize().width
    this.defaultPos = this.node.getPosition()
    this.blockMatrix = cc.find('blockMatrix', this.node.parent)
    this.addNodeEvent()
  }

  /** 设置所有的方块复原 */
  setBlockMatrixAll() {
    this.isMove = false
    const allBlock = this.node.children
    if (this.isSetBlockMartix()) {
      allBlock.forEach((node: cc.Node) => {
        const scripts = node.getComponent('miniBlock')
        scripts.setBlockMatrix()
      })
      this.checkBlockMatrix()
    }
    this.node.setPosition(this.defaultPos)
    this.node.scale = 1
  }

  /** 检查块矩阵是否能够消除 */
  checkBlockMatrix() {
    const blockMatrix = this.blockMatrix.children.map((node) => {
      const script = node.getComponent('block')
      return {
        node,
        script,
        blockState: script.blockState
      }
    })
    const { maxCol, maxRow } = Config
    const eliminateBlocks = []
    // 检查行
    for (let i = 0; i < maxCol; i++) {
      let temp = []
      for (let j = 0; j < maxRow; j++) {
        const block = blockMatrix[j + i * maxCol]
        if (block.blockState !== BLOCK_STATE.NON_EMPTY) break
        temp.push(block)
        if (temp.length === maxRow) {
          eliminateBlocks.push(temp)
        }
      }
    }

    // 检查列
    for (let i = 0; i < maxRow; i++) {
      let temp = []
      for (let j = 0; j < maxCol; j++) {
        const block = blockMatrix[i + j * maxRow]
        if (block.blockState !== BLOCK_STATE.NON_EMPTY) break
        temp.push(block)
        if (temp.length === maxCol) {
          eliminateBlocks.push(temp)
        }
      }
    }

    this.clearMatrixBlock(eliminateBlocks)
    console.log('eliminateBlocks:', eliminateBlocks)
  }

  /** 清理矩阵块 */
  clearMatrixBlock(eliminateBlocks: cc.Node[]) {
    const recursionPlay = async (els) => {
      if (els.length === 0) return
      const { script } = els.pop()
      script.playClearAni()
      await waitTime(Config.blockAniDelay)
      recursionPlay(els)
    }
    eliminateBlocks.forEach((els) => {
      recursionPlay(els)
    })
  }

  /**
   * 判断是否能够放入
   * @returns 
   */
  isSetBlockMartix() {
    const allBlock = this.node.children
    const filterBlock = []
    for (let i = 0; i < allBlock.length; i++) {
      const script = allBlock[i].getComponent('miniBlock')
      const { targetPos, targetNode } = script.getTargetMatrix()
      // 未获取到指定最短距离内的节点
      if (!targetNode) {
        return false
      }
      filterBlock.push({ targetPos, targetNode })
    }
    // 该目标节点是否为空
    const isEmpty = filterBlock.filter(({ targetNode }) => {
      const script = targetNode.getComponent('block')
      return script.blockState === BLOCK_STATE.NON_EMPTY
    }).length === 0
    if (!isEmpty) return false
    const allTargetNodeId = filterBlock.map(({ targetNode }) => targetNode.getSiblingIndex())
    // 索引是否重复
    const isRepeat = allTargetNodeId.find((_, i) => allTargetNodeId.includes(_, i + 1))
    return !isRepeat && isEmpty
  }

  addNodeEvent() {
    this.node.on(cc.Node.EventType.TOUCH_START, () => {
      this.isMove = true
      this.node.scale = 1.7
    }, this)

    this.node.on(cc.Node.EventType.TOUCH_END, () => {
      this.setBlockMatrixAll()
    }, this)

    this.node.on(cc.Node.EventType.TOUCH_MOVE, (e: cc.Event.EventTouch) => {

      if (this.isMove) {
        const pos: cc.Vec2 = e.getPreviousLocation()
        const viewW = this.viewWidth, viewH = this.viewHeight
        this.node.setPosition(pos.x - (viewW / 2), pos.y - (812 - (1624 - viewH) / 2))
      }
    }, this)
  }

  // update (dt) {}
}
