import { _decorator, Component, Node } from "cc";
import { GameCamera } from "./GameCamera";
import { Material } from "cc";
import { GameEvent, GameMgr } from "../../module_basic/scripts/GameMgr";
import { UITransform } from "cc";
import { size } from "cc";
import { Sprite } from "cc";
import { Vec2 } from "cc";
import { renderer } from "cc";
import {
  IFood,
  IGameData,
  IGamePlayer,
} from "../../module_basic/shared/protocols/public/game/GameTypeDef";
import { instantiate } from "cc";
import { GameResMgr } from "./GameResMgr";
import { Cell } from "./Cell";
import { UserMgr } from "../../module_basic/scripts/UserMgr";
import { PlayerMovement2D } from "./PlayerMovement2D";
import { PlayerController } from "./PlayerController";
import { UIGameJoystick } from "../ui_game_joystick/UIGameJoystick";
import { UIGameHUD } from "../ui_game_hud/UIGameHUD";
import { UIGameRank } from "../ui_game_rank/UIGameRank";
import { RoomMgr } from "../../module_basic/scripts/RoomMgr";
import { IRoomData, IUserData } from "../../module_basic/shared/types/RoomData";
import { UserInfo } from "../../module_basic/shared/types/UserInfo";
import { color } from "cc";
import { GameLocalData } from "./GameLocalData";
import { director } from "cc";
import { SceneUtil } from "../../core_tgx/base/SceneUtils";
import { ModuleDef } from "../../scripts/ModuleDef";
import { SceneDef } from "../../scripts/SceneDef";
import { GameSceneUtil } from "../../module_basic/scripts/GameSceneUtil";
import { UIGameResult } from "../../module_ball/ui_game/UIGameResult";
const { ccclass, property } = _decorator;

@ccclass("GameLocalScene")
export class GameLocalScene extends Component {
  @property(Node) mapRoot: Node;
  @property(Node) background: Node;
  @property(Node) objectsRoot: Node;
  @property(GameCamera) gameCamera: GameCamera;
  @property(Material) mapMaterial: Material;

  public static MAP_WIDTH = 10000;
  public static MAP_HEIGHT = 10000;

  private _cellMap: { [key: number]: Cell } = {};
  private _foodMap: { [key: number]: Node } = {};
  private _foodInfoMap: { [key: number]: IFood } = {};
  private _foodPool: Node[] = [];

  private _backgroundPass: renderer.Pass;
  private _handleEdgeFactor: number;

  private _selfPlayer: Cell = null;

  start() {
    let localUser: UserInfo = {
      uid: "local-me-uid-xxx-001",
    };
    UserMgr.inst.setUserInfo(localUser);

    let roomData: IRoomData = GameLocalData.ins.createLocalRoomData(
      localUser.uid
    );

    RoomMgr.inst.onNet_RoomDataSyncPush({
      data: roomData,
    });

    tgx.UIMgr.inst.showUI(UIGameJoystick);
    tgx.UIMgr.inst.showUI(UIGameHUD);
    // tgx.UIMgr.inst.showUI(UIGameRank);

    let selfPlayerInfo = GameLocalData.ins.mockIGamePlayer();
    let gameData = GameLocalData.ins.createLocalGameData(selfPlayerInfo);
    GameMgr.inst.localMode(gameData);
    GameMgr.inst.onNet_PlayerComesPush({
      player: selfPlayerInfo,
    });

    this.initBackground();

    this.createCell(selfPlayerInfo);

    let self = this;
    let intIn = setInterval(() => {
      if (
        !GameMgr.inst.gameData ||
        GameMgr.inst.gameData.gameState == "gameover"
      ) {
        clearInterval(intIn);
        return;
      }
      self.createFoods();
    }, 1000);

    director.on(GameEvent.GAME_EXIT, this.onGameExit, this);
  }

  onGameExit() {
    tgx.UIMgr.inst.closeAll();

    GameMgr.inst.localGameOver();

    UIGameResult.show();

   }
  protected onDestroy(): void {
    director.off(GameEvent.GAME_EXIT, this.onGameExit, this);
  }

  initBackground() {
    const extBorder = 4000;

    let gameData = GameMgr.inst.gameData;
    const realWidth = gameData.mapWidth + extBorder;
    const realHeight = gameData.mapHeight + extBorder;
    this.background.getComponent(UITransform).contentSize = size(
      realWidth,
      realHeight
    );

    //@en initialize the material parameters of the background.
    //@zh 初始化地图背景材质
    const halfWidth = gameData.mapWidth / 2;
    const halfHeight = gameData.mapHeight / 2;
    let spriteFrame = this.background.getComponent(Sprite).spriteFrame;
    let uvScale = new Vec2();
    let scaler = 0.6;
    //@en use uv scale to adapt the map size
    //@zh 使用uv缩放来适配地图大小
    uvScale.x = (realWidth / spriteFrame.width) * scaler;
    uvScale.y = (realHeight / spriteFrame.height) * scaler;
    this.mapMaterial.setProperty("uvScale", uvScale);
    this.mapMaterial.setProperty(
      "halfMapSize",
      new Vec2(halfWidth, halfHeight)
    );
    //this.mapMaterial.setProperty('edgeColor', new Vec4(1.0,0.0,0.0,1.0));
    //this.mapMaterial.setProperty('fadeOutRange', 1000.0);

    //@en save the material parameter handle for efficient setting of material parameters in update
    //@zh 保存材质参数相关句柄，方便在update中高效率地设置材质参数
    this._backgroundPass = this.mapMaterial.passes[0];
    this._handleEdgeFactor = this._backgroundPass.getHandle("edgeFactor");
  }
  tmpColor = color();

  createFoods() {
    let createCount = 1000 - Object.keys(this._foodMap).length;
    if (createCount <= 0) {
      return;
    }

    if (createCount > 100) {
      createCount = 100;
    }
    for (let i = 0; i < createCount; i++) {
      this.createFood(GameLocalData.ins.newFoodData());
    }
  }

  protected update(dt: number): void {
    let value = Math.sin(Date.now() / 50 / Math.PI);
    value = value * 0.5 + 0.5;
    this._backgroundPass.setUniform(this._handleEdgeFactor, value);

    this.checkFoodAndEat();
  }

  async createCell(player: IGamePlayer) {
    let newCell = instantiate(GameResMgr.inst.cellPrefab);
    this.objectsRoot.addChild(newCell);
    newCell.setWorldPosition(
      player.transform[0],
      player.transform[1],
      player.transform[2]
    );
    let cellComp = newCell.getComponent(Cell);
    cellComp.setPlayer(player);
    this._cellMap[player.playerId] = cellComp;

    if (player.uid == UserMgr.inst.uid) {
      this._selfPlayer = cellComp;
      let mv2d = newCell.addComponent(PlayerMovement2D);
      mv2d.needRotation = false;
      mv2d.moveSpeed = player.speed;
      mv2d.setPrecision(10);
      this.gameCamera.target = cellComp;
      newCell.addComponent(PlayerController);

      if (player.state == "moving") {
        mv2d.onMovement(player.transform[3], 1.0);
      }
    }
  }

  async createFood(fd: IFood) {
    // console.log("createFood", fd);
    let newFood = this._foodPool.pop();
    if (!newFood) {
      newFood = new Node();
      newFood.addComponent(Sprite);
    }

    this._foodInfoMap[fd.id] = fd;

    this.mapRoot.addChild(newFood);
    newFood.name = "food_" + fd.id;
    this._foodMap[fd.id] = newFood;

    let foodSprites = GameResMgr.inst.foodSprites;

    let sprf = foodSprites[fd.type % foodSprites.length];
    let spr = newFood.getComponent(Sprite);
    spr.spriteFrame = sprf;
    this.tmpColor.fromHEX(fd.color.toString(16));
    spr.color = this.tmpColor;

    let scale = (fd.radius * 2) / sprf.rect.width;
    newFood.setScale(scale, scale, 1.0);
    newFood.setRotationFromEuler(0, 0, Math.random() * 360);
    newFood.setWorldPosition(fd.x, fd.y, 0);
  }

  checkFoodAndEat() {
    if (!this._selfPlayer) {
      return;
    }

    for (let foodId in this._foodMap) {
      let foodNode = this._foodMap[foodId];
      let foodPos = foodNode.getWorldPosition();
      let playerPos = this._selfPlayer.node.getWorldPosition();
      let distance = Vec2.distance(foodPos, playerPos);
      let ddd = this._selfPlayer.player.radius / 1.5;
      if (distance < ddd) {
        delete this._foodMap[foodId];
        foodNode.removeFromParent();
        this._foodPool.push(foodNode);
        let oneAdd = this._foodInfoMap[foodId].radius / 10;
        delete this._foodInfoMap[foodId];
        this._selfPlayer.setRadius(this._selfPlayer.player.radius + oneAdd);
      }
    }
  }
}
