import { Object3D, Vector3 } from "three";
import { BatchedRenderer, QuarksLoader, QuarksUtil } from "three.quarks";
import { Template3d, UpdateController } from "@hitplay/playable_template";
import { ThreeC } from "./ThreeC";
import vfxLootableHitJson from "../resources/vfx/VFX_Lootable_Hit.json";
import vfxLootableDestroyJson from "../resources/vfx/VFX_Lootable_Destroy.json";

// Real designer-authored VFX for breakable props — found sitting unused in
// temp/ (exported from the quarks.art editor as plain Object3D.toJSON()
// groups, each a couple of ParticleEmitter children with their own tuned
// shape/speed/color/behaviors, referencing real textures like
// "novalines.webp" for the ray-streak look). Replaces the earlier
// hand-built SparkFxC, whose particles read as a soft dot-blob rather than
// the rays the reference screenshots called for — no amount of tuning a
// from-scratch system was going to match a real authored asset anyway.
//
// Loaded via plain Vite JSON imports + three.quarks' own QuarksLoader
// directly, NOT the SDK's quarksLoader()/ConvertToBase64WhenRelease
// (the pattern meshes.ts/images.ts use): quarksLoader() hardcodes
// `base64String.split(",")[1]` then atob() on it, which assumes it's
// always handed an actual base64 data: URI — true only once the build-time
// AST plugin rewrites the ConvertToBase64WhenRelease() call; in plain
// `vite dev` that call is a no-op passthrough returning a bare path
// string, which has no comma and would break the split/atob chain. A
// static JSON import sidesteps that entirely — Vite inlines JSON content
// into the bundle natively in every mode (dev, build, and the single-file
// export), no fetch, no base64 round-trip, no dev/build inconsistency.
const CLEANUP_DELAY_MS = 1500; // covers the longest emitter's duration+life in either prefab

export class PropVfxC {
  private static renderer: BatchedRenderer | null = null;
  private static hitTemplate: Object3D | null = null;
  private static destroyTemplate: Object3D | null = null;

  static init() {
    if (this.renderer) return;

    this.renderer = new BatchedRenderer();
    ThreeC.addToScene(this.renderer);
    UpdateController.Instance.onUpdate.addDelegate((delta) => this.renderer!.update(delta));

    // QuarksLoader.parse() is synchronous — the JSON already embeds every
    // texture as a base64 data: URI (see the "images" array in the
    // exported files), so there's no network fetch to wait on.
    const loader = new QuarksLoader(Template3d.manager);
    this.hitTemplate = loader.parse(vfxLootableHitJson);
    this.destroyTemplate = loader.parse(vfxLootableDestroyJson);

    // "Ground_Dirt" renders as a raw Mesh (RenderMode.Mesh) using a plain
    // PlaneGeometry (XY-plane, normal +Z) — unlike its "BreakingDust"
    // sibling in the same prefab, its own node has no compensating rotation
    // baked in, so unrotated it stands upright on its edge instead of lying
    // on the ground. -90° about local X maps that local Z normal to world
    // +Y (same convention as PayZoneC's ground-fill quad). Per-particle
    // startRotation spins around the emitter's own local Z (three.quarks
    // hardcodes UP=(0,0,1) for Mesh-mode rotation, ignoring the JSON's own
    // "axis" field), so this also keeps that spin flat around the
    // corrected world-up axis rather than tumbling the decal out of plane.
    const groundDirt = this.destroyTemplate.getObjectByName("Ground_Dirt");
    if (groundDirt) groundDirt.rotation.x = -Math.PI / 2;
  }

  static spawnHit(position: Vector3) {
    this.spawn(this.hitTemplate, position);
  }

  static spawnDestroy(position: Vector3) {
    this.spawn(this.destroyTemplate, position);
  }

  // Each call clones the loaded template (so concurrent bursts don't share
  // particle state), positions it at the world-space point, and forces
  // autoDestroy so every emitter in it removes itself once its particles
  // die — same self-cleanup contract as the old SparkFxC. The clone's root
  // Group itself doesn't get removed by that (only its ParticleEmitter
  // children do, once each one's particles finish), so it's swept from the
  // scene on a plain timeout sized to the prefabs' own durations.
  private static spawn(template: Object3D | null, position: Vector3) {
    if (!template || !this.renderer) return;

    const instance = template.clone();
    instance.position.copy(position);
    QuarksUtil.setAutoDestroy(instance, true);
    QuarksUtil.addToBatchRenderer(instance, this.renderer);
    ThreeC.addToScene(instance);
    QuarksUtil.play(instance);

    setTimeout(() => ThreeC.removeFromScene(instance), CLEANUP_DELAY_MS);
  }
}
