import { Vector3 } from "three";
import { CameraC_internal, UpdateController } from "@hitplay/playable_template";
import { ThreeC } from "./ThreeC";
import { resourceCounterBgSrc } from "../resources/images/images";

// How far in front of the camera (world units, along the screen ray) to
// place the projected anchor point — getWorldAnchorPosition() below finds
// the *direction* from the real DOM position via screen-to-NDC + unproject,
// but a single 2D screen point maps to a whole ray in 3D, so a depth still
// has to be chosen. Roughly matches the distance the old hand-picked local
// offset sat at, so the flight arcs read about the same as before.
const ANCHOR_DISTANCE = 2.5;

// Purely a prototype HUD — one counter for the one resource type that
// exists (wood). No install-banner-style config UI wiring; just a fixed
// DOM overlay mounted into the SDK's #ui container.
export class HudC {
  private static initialized = false;
  private static plateEl: HTMLElement;
  private static countEl: HTMLElement;
  private static lastDisplayedCount = -1;
  private static balanceGetter: (() => number) | null = null;

  static init() {
    if (this.initialized) return;
    this.initialized = true;

    this.buildDom();

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

  // Where collected resources fly to, and where PayZoneC's deposit flight
  // into the Pay Zone originates from — the plate's own right edge,
  // projected into 3D via the real DOM position (see chat: "дістати
  // позицію правого края юайки"), not a hand-picked local offset off the
  // camera like before. Recomputed from scratch on every call rather than
  // cached: it's only called once per resource-fly event (not per frame),
  // cheap enough, and this way it stays correct through window
  // resize/orientation changes for free.
  static getWorldAnchorPosition(): Vector3 {
    const canvasRect = ThreeC.renderer.domElement.getBoundingClientRect();
    const plateRect = this.plateEl.getBoundingClientRect();

    const screenX = plateRect.right;
    const screenY = plateRect.top + plateRect.height / 2;

    // NDC relative to the actual canvas box, not window.innerWidth/Height —
    // the SDK letterboxes/centers the canvas into a fixed 9:16 area (see
    // #ui/#editor in main.css), so the canvas's own bounding rect is the
    // only thing guaranteed to line up with the camera's projection.
    const ndcX = ((screenX - canvasRect.left) / canvasRect.width) * 2 - 1;
    const ndcY = -((screenY - canvasRect.top) / canvasRect.height) * 2 + 1;

    const camera = CameraC_internal.getCamera();
    const point = new Vector3(ndcX, ndcY, 0.5).unproject(camera);
    const direction = point.sub(camera.position).normalize();
    return camera.position.clone().addScaledVector(direction, ANCHOR_DISTANCE);
  }

  // The displayed number is a live balance, not a lifetime total — it
  // should rise as resources are collected and fall as they're delivered
  // into the Pay Zone (see chat). Injected rather than importing
  // ResourceC/PayZoneC directly, since PayZoneC already imports HudC (for
  // getWorldAnchorPosition) and importing back would cycle.
  static setBalanceGetter(getBalance: () => number) {
    this.balanceGetter = getBalance;
  }

  // Layout/styling lives in src/css/ui.css (.resource-hud/__plate/__count) —
  // only the background image itself is set here, since its actual path
  // (base64 in a real build, a bare path in dev) is only known via the
  // asset import, not something a static CSS file can reference.
  //
  // Two nested divs, not one: .resource-hud positions/sizes and plays the
  // one-shot mount animation; .resource-hud__plate (background + number
  // together) is the separate element the update-bump animates — see the
  // comment in ui.css for why these can't share one element without the
  // two animations fighting each other.
  private static buildDom() {
    const holder = document.createElement("div");
    holder.className = "resource-hud";

    const plate = document.createElement("div");
    plate.className = "resource-hud__plate";
    plate.style.backgroundImage = `url(${resourceCounterBgSrc})`;

    const count = document.createElement("span");
    count.className = "resource-hud__count";
    count.textContent = "0";

    plate.appendChild(count);
    holder.appendChild(plate);

    const uiRoot = document.getElementById("ui") ?? document.body;
    uiRoot.appendChild(holder);

    this.plateEl = plate;
    this.countEl = count;
  }

  private static update() {
    if (!this.balanceGetter) return;
    const count = this.balanceGetter();
    if (count === this.lastDisplayedCount) return;
    this.lastDisplayedCount = count;
    this.countEl.textContent = String(count);

    // The actual "pop" is a CSS animation on the whole plate (.is-bumping,
    // see ui.css), not just the digit — this only toggles the class,
    // forcing a reflow in between so it restarts cleanly even if the count
    // changes again before the previous bump finished (e.g. PayZoneC
    // draining resources every 0.3s).
    this.plateEl.classList.remove("is-bumping");
    void this.plateEl.offsetWidth;
    this.plateEl.classList.add("is-bumping");
  }
}
