import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
import { Object3D } from "three";
import { findMenuController } from "./findMenuController.js";
import type { MenuController } from "./scripts/MenuController.js";

/**
 * When Unity/Needle exports a dish root without glTF mesh data (e.g. GLB was a Git LFS pointer
 * at import time), inject geometry from a bundled standalone GLB matching the object name.
 */
const DISH_GLBS: Record<string, string> = {
  "cc0_-_pizza_salami": "include/dishes/cc0_-_pizza_salami.glb",
};

function countRenderableMeshes(root: Object3D): number {
  let n = 0;
  root.traverse((o) => {
    const m = o as Object3D & { isMesh?: boolean };
    if (m.isMesh) n += 1;
  });
  return n;
}

function resolveIncludeUrl(relative: string): string {
  const base = import.meta.env.BASE_URL ?? "./";
  const normalized = base.endsWith("/") ? base : `${base}/`;
  return new URL(relative, new URL(normalized, window.location.href)).href;
}

export async function ensureDishMeshes(
  menu: MenuController,
): Promise<void> {
  const loader = new GLTFLoader();
  for (const dish of menu.dishes) {
    if (!dish) continue;
    const rel = DISH_GLBS[dish.name];
    if (!rel) continue;
    if (countRenderableMeshes(dish) > 0) continue;
    if (dish.children.some((child) => child.name === `${dish.name}_mesh`)) continue;

    const url = resolveIncludeUrl(rel);
    const gltf = await loader.loadAsync(url);
    gltf.scene.name = `${dish.name}_mesh`;
    dish.add(gltf.scene);
  }
}

function initDishMeshFallback(): void {
  const needle = document.querySelector("needle-engine");
  if (!needle) return;

  const run = async (): Promise<void> => {
    try {
      const ctx = await needle.getContext();
      const menu = findMenuController(ctx);
      if (menu) await ensureDishMeshes(menu);
    } catch (err) {
      console.warn("[dishMeshFallback] Could not inject dish meshes:", err);
    }
  };

  needle.addEventListener("loadfinished", () => void run());
  needle.addEventListener("menu-dishes-updated", () => void run());
}

initDishMeshFallback();
