import { Assets, Container, PointData, Sprite, Ticker } from "pixi.js";
import bgImg from "@/assets/GamePage/bg.jpg";
import { Joystick } from "@/pages/GamePage/Components/Joystick.ts";
import 'pixi.js/math-extras';
import { Snake } from "@/pages/GamePage/Components/Snake.ts";
import { ElementMgr } from "@/pages/GamePage/Components/ElementMgr.ts";
import { Ele, EleConfig, GameConfig, mapTop, winSize } from "@/pages/GamePage/config/Config.ts";
import { collisionSys } from "@/pages/GamePage/GamePage.tsx";
import {Element} from "./Components/Element/Element.ts";

import { Response, Body } from "detect-collisions";
import gameStore from "@/store/gameStore.ts";
import { ScoreBubble } from "@/pages/GamePage/Components/ScoreBubble.ts";
import { IReactionDisposer, reaction } from "mobx";
import { Ease, Tween } from "@/pages/GamePage/tween";

export class Game extends Container {

  joystick: Joystick = null;
  private snake: Snake;
  private mapCtn: Container;

  private elementMgr: ElementMgr;

  lvDisposer: IReactionDisposer = null;

  constructor() {
    super();
    this.initUI();

    this.lvDisposer = reaction(
      () => gameStore.gameInfo.level,
      (level) => {
        if(level == 0) return;
        const skin = GameConfig.levelCfg[level].skin;
        const sp = this.addChild(new Sprite(Assets.get(`蛇/${skin}/tip.png`)));
        sp.position.set(375, winSize.height / 2 + 100);
        sp.anchor.set(0.5, 0.5);
        sp.scale.set(0, 0);
        Tween.get(sp.scale)
          .to({ x: 1, y: 1 }, 444, Ease.backOut)
          .wait(1500)
          .call(() => {
            sp.removeFromParent();
          });
      }
    );
  }

  initUI() {

    const bg = this.addChild(new Sprite());
    Assets.load(bgImg).then((texture) => bg.texture = texture);

    this.joystick = this.addChild(new Joystick());
    this.joystick.visible = false;

    this.mapCtn = this.addChild(new Container());
    this.mapCtn.y = mapTop;

    this.elementMgr = new ElementMgr(this.mapCtn);
    this.elementMgr.start();

    this.snake = this.mapCtn.addChild(new Snake());
    this.snake.init();

    this.on("pointerdown", this.onPointerDown, this);
    this.on("pointerup", this.onPointerUp, this);
  }

  onPointerDown(e: any) {
    this.joystick.visible = true;
    this.joystick.x = e.data.global.x;
    this.joystick.y = e.data.global.y;
    this.joystick.handlePointerDown(e);
  }

  onPointerUp(e: any) {
    this.joystick.visible = false;
  }

  colliderCallback = (result: Response) => {
    const {
      a, b,
      aInB, bInA,
      overlap, overlapV, overlapN
    } = result;

    const { userData: aData } = a as Body<{ ele: Element, snake: boolean, isNeg: boolean }>;
    const { userData: bData } = b as Body<{ ele: Element, snake: boolean, isNeg: boolean }>;

    if (aData?.snake == bData?.snake) return;

    const ele = aData?.ele || bData?.ele;

    const { id } = ele;

    const { score, neg } = EleConfig[id];

    const isNeg = !!(aData?.isNeg || bData?.isNeg);

    if (isNeg != (!!neg)) return;

    ele.beEaten(this.snake.head);

    if (id === Ele.ZongZi) {
      this.snake.useMagnet();
    } else {
      this.snake.addEnergy(score);
      this.addScore(score, ele.position);
    }

  }

  addScore(score: number, pos: PointData) {
    gameStore.addScore(score);
    const bubble = this.mapCtn.addChild(new ScoreBubble(score));
    bubble.position.set(pos.x + 20, pos.y - 20);
  }

  onUpdate(time: Ticker) {
    const dt = time.deltaMS / 1000;
    this.snake.dir.copyFrom(this.joystick.dir);
    this.snake.onUpdate(dt);
    collisionSys.checkAll(this.colliderCallback);
  }

  destroy() {
    this.lvDisposer();
    super.destroy();
  }
}
