import {
  Node,
  Prefab,
  instantiate,
  Sprite,
  SpriteFrame,
  UITransform,
  Vec3,
} from "cc";
import { BoardShapes, BoardShapeName } from "./BoardShape";

export interface LevelConfig {
  rows?: number;
  cols?: number;
  blockSize?: number;
  tileTypes?: number;
  currentShape?: BoardShapeName;
  isTutorial?: boolean;
  fixedBoard?: number[][];
}

export class LevelBuilder {
  public board: number[][] = [];
  public blockNodes: (Node | null)[][] = [];
  public rows: number = 0;
  public cols: number = 0;

  private node: Node;
  private blockPrefab: Prefab;
  private spriteFrames: SpriteFrame[] = [];
  private blockSize: number = 100;
  private tileTypes: number = 5;

  public currentShape: BoardShapeName = "rectangle";
  private fixedBoard: number[][] | null = null;

  constructor(
    node: Node,
    blockPrefab: Prefab,
    spriteFrames: SpriteFrame[],
    config?: LevelConfig,
  ) {
    this.node = node;
    this.blockPrefab = blockPrefab;
    this.spriteFrames = spriteFrames;

    if (config) {
      this.blockSize = config.blockSize ?? this.blockSize;
      this.tileTypes = config.tileTypes ?? this.tileTypes;
      if (config.currentShape) this.currentShape = config.currentShape;
      if (config.fixedBoard) this.fixedBoard = config.fixedBoard;
    }
  }

  public buildBoard(): void {
    if (this.fixedBoard) {
      this.buildFixedBoard();
      return;
    }

    const shapeTemplate = BoardShapes[this.currentShape];
    if (!shapeTemplate) throw new Error(`Shape "${this.currentShape}" 未定义`);

    const maxCols = Math.max(...shapeTemplate.map((row) => row.length));
    const rows = shapeTemplate.length;

    // 自动补齐矩形
    const fixedTemplate: number[][] = [];
    for (let r = 0; r < rows; r++) {
      fixedTemplate[r] = [];
      for (let c = 0; c < maxCols; c++) {
        fixedTemplate[r][c] = shapeTemplate[r][c] ?? 0;
      }
    }

    // 收集可用格子
    const validCells = [];
    for (let r = 0; r < rows; r++) {
      for (let c = 0; c < maxCols; c++) {
        if (fixedTemplate[r][c] === 1) validCells.push({ r, c });
      }
    }

    if (validCells.length % 2 !== 0) throw new Error("有效格子数量必须为偶数");

    // 随机生成配对
    let tiles: number[] = [];
    for (let i = 0; i < validCells.length / 2; i++) {
      const id = i % this.tileTypes;
      tiles.push(id, id);
    }
    for (let i = tiles.length - 1; i > 0; i--) {
      const j = Math.floor(Math.random() * (i + 1));
      [tiles[i], tiles[j]] = [tiles[j], tiles[i]];
    }

    let tileIndex = 0;
    this.board = [];
    this.blockNodes = [];
    this.rows = rows;
    this.cols = maxCols;

    for (let r = 0; r < rows; r++) {
      this.board[r] = [];
      this.blockNodes[r] = [];
      for (let c = 0; c < maxCols; c++) {
        if (fixedTemplate[r][c] === 1) {
          const tileId = tiles[tileIndex++];
          this.board[r][c] = tileId;
          const block = this.createNormalBlock(tileId);
          block.setPosition(this.getPos(r, c));
          this.node.addChild(block);
          this.blockNodes[r][c] = block;
        } else if (fixedTemplate[r][c] === -1) {
          this.board[r][c] = -1;
          this.blockNodes[r][c] = null;
        } else {
          this.board[r][c] = -2;
          const stone = this.createStoneBlock();
          stone.setPosition(this.getPos(r, c));
          this.node.addChild(stone);
          this.blockNodes[r][c] = stone;
        }
      }
    }
  }

  private buildFixedBoard() {
    this.rows = this.fixedBoard.length;
    this.cols = this.fixedBoard[0].length;
    this.board = [];
    this.blockNodes = [];

    for (let r = 0; r < this.rows; r++) {
      this.board[r] = [];
      this.blockNodes[r] = [];
      for (let c = 0; c < this.cols; c++) {
        const val = this.fixedBoard[r][c];
        this.board[r][c] = val;

        if (val >= 0) {
          const block = this.createNormalBlock(val);
          block.setPosition(this.getPos(r, c));
          this.node.addChild(block);
          this.blockNodes[r][c] = block;
        } else if (val === -1) {
          this.blockNodes[r][c] = null;
        } else if (val === -2) {
          const stone = this.createStoneBlock();
          stone.setPosition(this.getPos(r, c));
          this.node.addChild(stone);
          this.blockNodes[r][c] = stone;
        }
      }
    }
  }

  private createNormalBlock(tileId: number) {
    const block = instantiate(this.blockPrefab);
    const bgNode = block.getChildByName("Bg");
    const bgUI =
      bgNode.getComponent(UITransform) ?? bgNode.addComponent(UITransform);
    bgUI.setContentSize(this.blockSize, this.blockSize);

    const iconNode = block.getChildByName("Icon");
    const iconUI =
      iconNode.getComponent(UITransform) ?? iconNode.addComponent(UITransform);
    const iconUI_sprite = iconNode.getComponent(Sprite)!;
    iconUI_sprite.spriteFrame = this.spriteFrames[tileId];
    iconUI.setContentSize(this.blockSize * 0.7, this.blockSize * 0.7);
    iconNode.setPosition(0, 0, 0);

    return block;
  }

  private createStoneBlock() {
    const stone = instantiate(this.blockPrefab);
    const bgNode = stone.getChildByName("Bg");
    const bgUI =
      bgNode.getComponent(UITransform) ?? bgNode.addComponent(UITransform);
    bgUI.setContentSize(this.blockSize, this.blockSize);

    const iconNode = stone.getChildByName("Icon");
    iconNode.active = false;

    return stone;
  }

  private getPos(row: number, col: number): Vec3 {
    const x =
      col * this.blockSize -
      (this.cols * this.blockSize) / 2 +
      this.blockSize / 2;
    const y =
      (this.rows * this.blockSize) / 2 -
      row * this.blockSize -
      this.blockSize / 2;
    return new Vec3(x, y, 0);
  }

  /**
   * 新建 UI 节点，并设置类型和位置
   */
  public createBlockNode(type: number, r: number, c: number): Node {
    let block: Node;

    if (type >= 0) {
      // 普通方块
      block = this.createNormalBlock(type);
    } else if (type === -2) {
      // 石头障碍
      block = this.createStoneBlock();
    } else {
      // 空格不需要节点
      return null!;
    }

    block.setPosition(this.getPos(r, c));
    this.node.addChild(block);

    return block;
  }

  /**
   * 更新节点的贴图/颜色/数字等显示
   */
  public setBlockType(node: Node, type: number): void {
    if (!node) return;

    const iconNode = node.getChildByName("Icon");
    if (!iconNode) return;

    if (type >= 0) {
      // 普通方块
      iconNode.active = true;
      const iconUI =
        iconNode.getComponent(UITransform) ??
        iconNode.addComponent(UITransform);
      const iconUI_sprite = iconNode.getComponent(Sprite)!;
      iconUI_sprite.spriteFrame = this.spriteFrames[type];
      iconUI.setContentSize(this.blockSize * 0.7, this.blockSize * 0.7);
      iconNode.setPosition(0, 0, 0);
    } else if (type === -2) {
      // 石头
      iconNode.active = false;
    } else {
      // 空格
      iconNode.active = false;
    }
  }

  /**
   * 更新节点的坐标位置（UI 上）
   */
  public setBlockPosition(node: Node, r: number, c: number): void {
    if (!node) return;
    node.setPosition(this.getPos(r, c));
  }

  /**
   * 销毁节点或隐藏
   */
  public destroyBlockNode(node: Node): void {
    if (!node) return;
    node.destroy(); // 如果想复用可改为 node.active = false
  }
}
