import { EasyEvent, UpdateController } from "@24tools/playable_template";
import { Box3, Object3D, Vector3 } from "three";
import { Player } from "../Presets/Player";
import {
  findInteractiveZoneFromMap,
  INTERACTIVE_ZONE_NAME,
  isInsideInteractiveZoneXZ,
  refreshInteractiveZoneBounds,
} from "./MapInteractiveZone";

export class DepositZoneC {
  static readonly onPlayerEnter = new EasyEvent<{}>();
  static readonly onPlayerExit = new EasyEvent<{}>();

  private static inited = false;
  private static zone: Object3D | null = null;
  private static bounds = new Box3();
  private static playerInside = false;
  private static playerPosition = new Vector3();

  static init(mapObject: Object3D) {
    if (this.inited) return;

    this.zone = findInteractiveZoneFromMap(mapObject);
    if (!this.zone) {
      console.warn(`Deposit zone not found: ${INTERACTIVE_ZONE_NAME}`);
      return;
    }

    this.inited = true;
    refreshInteractiveZoneBounds(this.zone, this.bounds);

    UpdateController.Instance.onUpdate.addDelegate(() => {
      this.update();
    });
  }

  static get isPlayerInside() {
    return this.playerInside;
  }

  private static update() {
    this.getPlayerPosition(this.playerPosition);
    refreshInteractiveZoneBounds(this.zone!, this.bounds);
    this.updatePlayerInside(this.playerPosition);
  }

  private static getPlayerPosition(out: Vector3) {
    const body = Player.physics?.getPhysicsBody();
    if (body) {
      return out.set(body.position.x, body.position.y, body.position.z);
    }

    return Player.getWorldPosition().copy(out);
  }

  private static updatePlayerInside(playerPosition: Vector3) {
    const inside = isInsideInteractiveZoneXZ(this.bounds, playerPosition);
    if (inside === this.playerInside) return;

    this.playerInside = inside;
    if (inside) {
      console.log(`[DepositZoneC] enter deposit zone: ${INTERACTIVE_ZONE_NAME}`);
      this.onPlayerEnter.Invoke({});
      return;
    }

    console.log(`[DepositZoneC] exit deposit zone: ${INTERACTIVE_ZONE_NAME}`);
    this.onPlayerExit.Invoke({});
  }
}
