// quiz-ufo-builder.jsx
// UFO Builder: tap-card builder with body/window/launcher/energy categories.
// Owns its art constants (UFO_PART_ART, UFO_LAB_ART, UFO_ANGEL_RING_FRAMES).

const UFO_BUILDER_GROUPS = [
  {
    id: "body",
    label: "Body",
    options: [
      {
        id: "bronzeHull",
        label: "Saucer",
        icon: "🛸",
        cue: "classic hull",
        addText: "The classic saucer body gives every module a steady socket.",
      },
      {
        id: "tearDrop",
        label: "Tear drop",
        icon: "🟠",
        cue: "inverted body",
        addText: "The inverted teardrop body makes the craft feel deep and heavy.",
      },
      {
        id: "angelRings",
        label: "Angel rings",
        icon: "✴",
        cue: "rotating circles",
        addText: "The angel-ring body spins nested circles around a bright core.",
      },
    ],
  },
  {
    id: "windows",
    label: "Windows",
    options: [
      {
        id: "blueWindows",
        label: "Blue portholes",
        icon: "🔵",
        cue: "front socket",
        addText: "The blue porthole plugs into the front window socket.",
      },
      {
        id: "smileWindows",
        label: "Smile face",
        icon: "😊",
        cue: "friendly panel",
        addText: "The smile panel makes the front socket friendly.",
      },
      {
        id: "radarWindows",
        label: "Radar dots",
        icon: "🟣",
        cue: "sensor panel",
        addText: "The radar lens turns the front socket into a scanner.",
      },
    ],
  },
  {
    id: "launcher",
    label: "Side Tool",
    options: [
      {
        id: "orbPods",
        label: "Orb pods",
        icon: "🔴",
        cue: "side sockets",
        addText: "Orb pods click into the side sockets.",
      },
      {
        id: "sparkTrail",
        label: "Spark tail",
        icon: "✨",
        cue: "rear socket",
        addText: "The spark nozzle plugs into the rear socket.",
      },
      {
        id: "quietBeam",
        label: "Energy beam",
        icon: "💡",
        cue: "bottom socket",
        addText: "The energy beam projects from the bottom landing socket.",
      },
      {
        id: "dropUfos",
        label: "Scout trio",
        icon: "💧",
        cue: "helper ships",
        addText: "The scout trio docks below the UFO and floats out.",
      },
    ],
  },
  {
    id: "energy",
    label: "Energy",
    options: [
      {
        id: "starDrive",
        label: "Star drive",
        icon: "✴",
        cue: "eight-point power",
        addText: "The star drive gives the UFO zippy energy.",
      },
      {
        id: "lightBurst",
        label: "Light burst",
        icon: "💥",
        cue: "appear in a flash",
        addText: "A light burst helps the UFO appear in a happy flash.",
      },
      {
        id: "cometGlow",
        label: "Comet glow",
        icon: "☄",
        cue: "purple speed glow",
        addText: "A comet glow makes the UFO feel fast and magical.",
      },
      {
        id: "redFire",
        label: "Red fire",
        icon: "🔥",
        cue: "rocket flame path",
        addText: "A red fire path burns like a regular rocket trail.",
      },
    ],
  },
];

const DEFAULT_UFO_BUILD = {
  body: "bronzeHull",
  windows: null,
  launcher: null,
  energy: null,
};

const UFO_LAB_ART = {
  stage: "data/generated-assets/ufo-lab/ufo-lab-stage-bg.png",
  body: {
    bronzeHull: "data/generated-assets/ufo-lab/ufo-chassis.png",
    tearDrop: "data/generated-assets/ufo-lab/ufo-body-teardrop.png",
    angelRings: "data/generated-assets/ufo-lab/ufo-body-angel-rings.png",
  },
};

const UFO_ANGEL_RING_FRAMES = [0, 1, 2, 3].map(
  (index) =>
    `data/generated-assets/ufo-lab/angel-rings-rotation/angel-rings-frame-${index}.png?v=20260512-ring-rotation`,
);

const UFO_PART_ART = {
  bronzeHull: UFO_LAB_ART.body.bronzeHull,
  tearDrop: UFO_LAB_ART.body.tearDrop,
  angelRings: UFO_ANGEL_RING_FRAMES[0],
  blueWindows: "data/generated-assets/ufo-lab/ufo-part-blueWindows.png",
  smileWindows: "data/generated-assets/ufo-lab/ufo-part-smileWindows.png",
  radarWindows: "data/generated-assets/ufo-lab/ufo-part-radarWindows.png",
  orbPods: "data/generated-assets/ufo-lab/ufo-part-orbPods.png",
  sparkTrail: "data/generated-assets/ufo-lab/ufo-part-sparkTrail.png",
  quietBeam: "data/generated-assets/ufo-lab/ufo-part-quietBeam-v2.png",
  dropUfos: "data/generated-assets/ufo-lab/ufo-part-dropUfos.png",
  starDrive: "data/generated-assets/ufo-lab/ufo-part-starDrive.png",
  lightBurst: "data/generated-assets/ufo-lab/ufo-part-lightBurst.png",
  cometGlow: "data/generated-assets/ufo-lab/ufo-part-cometGlow.png",
  redFire: "data/generated-assets/ufo-lab/ufo-part-redFire.png?v=20260512-red-fire-gen",
};

function ufoOptionFor(groupId, optionId) {
  const group = UFO_BUILDER_GROUPS.find((item) => item.id === groupId);
  return group?.options.find((option) => option.id === optionId) || group?.options[0];
}

function ufoBuildSummary(build) {
  return UFO_BUILDER_GROUPS
    .map((group) => (build[group.id] ? ufoOptionFor(group.id, build[group.id])?.label : null))
    .filter(Boolean)
    .join(" + ");
}

function defaultUfoModulePosition(groupId, partId, bodyId) {
  if (groupId === "windows") {
    return {
      x: 50,
      y: bodyId === "tearDrop" ? 52 : 56,
    };
  }
  if (groupId === "launcher") {
    if (partId === "orbPods") return { x: 50, y: 58 };
    if (partId === "sparkTrail") return { x: 76, y: 57 };
    if (partId === "quietBeam") {
      if (bodyId === "bronzeHull") return { x: 50, y: 91 };
      if (bodyId === "tearDrop") return { x: 50, y: 88 };
      return { x: 50, y: 86 };
    }
    if (partId === "dropUfos") {
      return { x: 50, y: bodyId === "angelRings" ? 83 : 86 };
    }
    return { x: 50, y: 78 };
  }
  if (groupId === "energy") {
    if (partId === "lightBurst") return { x: 70, y: 39 };
    if (partId === "cometGlow") return { x: 76, y: 57 };
    if (partId === "redFire") return { x: 50, y: 83 };
    if (bodyId === "angelRings") return { x: 76, y: 30 };
    return { x: 72, y: 34 };
  }
  return { x: 50, y: 50 };
}

function clampUfoPlacement(value, min = 8, max = 92) {
  return Math.max(min, Math.min(max, Math.round(value)));
}

function UfoBuilderLevel({ onExit }) {
  const [build, setBuild] = useState(DEFAULT_UFO_BUILD);
  const [partPositions, setPartPositions] = useState({});
  const [energyModules, setEnergyModules] = useState([]);
  const [selectedModule, setSelectedModule] = useState(null);
  const [savedBuilds, setSavedBuilds] = useState([]);
  const [message, setMessage] = useState("Tap one module for each socket. Watch it snap onto the lab UFO.");
  const [beamOn, setBeamOn] = useState(false);
  const [dragPreview, setDragPreview] = useState(null);
  const craftRef = React.useRef(null);
  const stageRef = React.useRef(null);
  const activePointerDragRef = React.useRef(null);
  const suppressNextClickRef = React.useRef(false);
  const buildSummary = ufoBuildSummary(build);
  const buildKey = JSON.stringify({ build, partPositions, energyModules });
  const savedCurrentBuild = savedBuilds.some((item) => item.key === buildKey);
  const flightChecks = [
    { id: "body", label: "Hull", ready: Boolean(build.body), hint: "A body holds every part." },
    { id: "windows", label: "Window", ready: Boolean(build.windows), hint: "Windows help pilots see." },
    { id: "launcher", label: "Tool", ready: Boolean(build.launcher), hint: "Tools help the craft work." },
    { id: "energy", label: "Energy", ready: energyModules.length > 0, hint: "Energy powers the flight." },
  ];

  const selectPart = (group, option, placement = null) => {
    if (group.id !== "body" && group.id !== "energy" && build[group.id] === option.id) {
      setBuild((current) => ({ ...current, [group.id]: null }));
      setPartPositions((current) => {
        const next = { ...current };
        delete next[group.id];
        return next;
      });
      setSelectedModule(null);
      setMessage(`${option.label} is unplugged. Pick it again when you want it back.`);
      setBeamOn(false);
      playKidSound("pop");
      return;
    }

    if (group.id === "energy") {
      const base = placement || defaultUfoModulePosition(group.id, option.id, build.body);
      const count = energyModules.length;
      const nextModule = {
        id: `energy-${Date.now()}-${count}`,
        partId: option.id,
        x: clampUfoPlacement(base.x + (placement ? 0 : (count % 3) * 6 - 6)),
        y: clampUfoPlacement(base.y + (placement ? 0 : Math.floor(count / 3) * 8)),
        rotation: option.id === "redFire" ? 180 : 0,
      };
      setBuild((current) => ({ ...current, energy: option.id }));
      setEnergyModules((current) => [...current, nextModule].slice(-8));
      setSelectedModule({ type: "energy", id: nextModule.id });
      setMessage(`${option.addText} Add another energy, drag it, rotate it, or remove it.`);
      setBeamOn(false);
      playKidSound("boop");
      return;
    }

    setBuild((current) => ({ ...current, [group.id]: option.id }));
    setPartPositions((current) => {
      if (group.id === "body") return current;
      const next = { ...current };
      if (placement) {
        next[group.id] = { ...placement, rotation: current[group.id]?.rotation || 0 };
      } else {
        delete next[group.id];
      }
      return next;
    });
    setSelectedModule(group.id === "body" ? null : { type: "single", groupId: group.id });
    setMessage(`${option.addText} Now try it with a different ${group.label.toLowerCase()}.`);
    setBeamOn(false);
    playKidSound("boop");
  };

  const placementFromPoint = (clientX, clientY, forgiving = false) => {
    const box = craftRef.current?.getBoundingClientRect();
    if (!box) return null;
    const margin = forgiving ? Math.min(120, box.width * 0.28) : 0;
    if (
      clientX < box.left - margin ||
      clientX > box.right + margin ||
      clientY < box.top - margin ||
      clientY > box.bottom + margin
    ) {
      return null;
    }
    return {
      x: clampUfoPlacement(((clientX - box.left) / box.width) * 100),
      y: clampUfoPlacement(((clientY - box.top) / box.height) * 100),
    };
  };

  const placementFromEvent = (event) => placementFromPoint(event.clientX, event.clientY, true);

  const dragPartData = (event, group, part) => {
    if (!event.dataTransfer) return;
    event.dataTransfer.effectAllowed = group.id === "body" ? "copy" : "move";
    event.dataTransfer.setData(
      "application/x-ufo-part",
      JSON.stringify({ groupId: group.id, partId: part.id }),
    );
  };

  const dropPart = (event) => {
    event.preventDefault();
    const raw = event.dataTransfer.getData("application/x-ufo-part");
    if (!raw) return;
    let data = null;
    try {
      data = JSON.parse(raw);
    } catch {
      return;
    }
    const group = UFO_BUILDER_GROUPS.find((item) => item.id === data.groupId);
    const option = group?.options.find((part) => part.id === data.partId);
    if (!group || !option) return;
    selectPart(group, option, group.id === "body" ? null : placementFromEvent(event));
  };

  const beginPointerDrag = (event, group, part, existingModule = null) => {
    if (!group || !part) return;
    event.preventDefault();
    event.stopPropagation();
    activePointerDragRef.current = {
      group,
      part,
      existingModule,
      startX: event.clientX,
      startY: event.clientY,
      x: event.clientX,
      y: event.clientY,
      moved: false,
    };
    setDragPreview({
      x: event.clientX,
      y: event.clientY,
      src: UFO_PART_ART[part.id],
      partId: part.id,
      label: part.label,
    });
    event.currentTarget.setPointerCapture?.(event.pointerId);
  };

  React.useEffect(() => {
    const onPointerMove = (event) => {
      const drag = activePointerDragRef.current;
      if (!drag) return;
      const distance = Math.hypot(event.clientX - drag.startX, event.clientY - drag.startY);
      const moved = drag.moved || distance > 7;
      activePointerDragRef.current = {
        ...drag,
        x: event.clientX,
        y: event.clientY,
        moved,
      };
      setDragPreview((current) =>
        current
          ? {
              ...current,
              x: event.clientX,
              y: event.clientY,
              overPad: Boolean(placementFromPoint(event.clientX, event.clientY, true)),
            }
          : current,
      );
    };

    const onPointerUp = (event) => {
      const drag = activePointerDragRef.current;
      if (!drag) return;
      activePointerDragRef.current = null;
      setDragPreview(null);
      suppressNextClickRef.current = true;
      window.setTimeout(() => {
        suppressNextClickRef.current = false;
      }, 0);
      if (!drag.moved) {
        selectPart(drag.group, drag.part);
        return;
      }
      const placement = placementFromPoint(event.clientX, event.clientY, true);
      if (!placement) {
        setMessage("Drop modules on the glowing lab UFO pad.");
        playKidSound("pop");
        return;
      }
      if (drag.existingModule?.type === "energy") {
        setEnergyModules((current) =>
          current.map((module) =>
            module.id === drag.existingModule.id ? { ...module, ...placement } : module,
          ),
        );
        setSelectedModule({ type: "energy", id: drag.existingModule.id });
        setMessage(`${drag.part.label} moved. Drag another module or rotate it.`);
        playKidSound("boop");
        return;
      }
      if (drag.existingModule?.type === "single") {
        setPartPositions((current) => ({
          ...current,
          [drag.group.id]: {
            ...placement,
            rotation: current[drag.group.id]?.rotation || 0,
          },
        }));
        setSelectedModule({ type: "single", groupId: drag.group.id });
        setMessage(`${drag.part.label} moved. Rotate it or try another module.`);
        playKidSound("boop");
        return;
      }
      selectPart(drag.group, drag.part, drag.group.id === "body" ? null : placement);
    };

    const onPointerCancel = () => {
      activePointerDragRef.current = null;
      setDragPreview(null);
    };

    window.addEventListener("pointermove", onPointerMove);
    window.addEventListener("pointerup", onPointerUp);
    window.addEventListener("pointercancel", onPointerCancel);
    return () => {
      window.removeEventListener("pointermove", onPointerMove);
      window.removeEventListener("pointerup", onPointerUp);
      window.removeEventListener("pointercancel", onPointerCancel);
    };
  }, [build, energyModules]);

  const rotateSelected = (amount) => {
    if (!selectedModule) return;
    if (selectedModule.type === "energy") {
      setEnergyModules((current) =>
        current.map((item) =>
          item.id === selectedModule.id
            ? { ...item, rotation: ((item.rotation || 0) + amount + 360) % 360 }
            : item,
        ),
      );
    } else {
      setPartPositions((current) => {
        const groupId = selectedModule.groupId;
        const partId = build[groupId];
        if (!partId) return current;
        const base =
          current[groupId] || defaultUfoModulePosition(groupId, partId, build.body);
        return {
          ...current,
          [groupId]: { ...base, rotation: ((base.rotation || 0) + amount + 360) % 360 },
        };
      });
    }
    setMessage("Rotated that piece. Keep turning it until the build feels right.");
    playKidSound("boop");
  };

  const removeSelected = () => {
    if (!selectedModule) return;
    if (selectedModule.type === "energy") {
      setEnergyModules((current) => current.filter((item) => item.id !== selectedModule.id));
    } else if (selectedModule.groupId !== "body") {
      setBuild((current) => ({ ...current, [selectedModule.groupId]: null }));
      setPartPositions((current) => {
        const next = { ...current };
        delete next[selectedModule.groupId];
        return next;
      });
    }
    setSelectedModule(null);
    setMessage("Piece removed. Pick a tool or energy to plug something else in.");
    playKidSound("pop");
  };

  const materialize = () => {
    setBeamOn(true);
    setMessage(`Your ${buildSummary} materializes. What could this one do?`);
    playKidSound("chime");
  };

  const surpriseBuild = () => {
    const nextBuild = {};
    UFO_BUILDER_GROUPS.forEach((group, index) => {
      const currentIndex = group.options.findIndex((option) => option.id === build[group.id]);
      const nextIndex = (Math.max(currentIndex, 0) + index + 1) % group.options.length;
      nextBuild[group.id] = group.options[nextIndex].id;
    });
    setBuild(nextBuild);
    setPartPositions({});
    setEnergyModules([
      {
        id: `energy-${Date.now()}`,
        partId: nextBuild.energy,
        ...defaultUfoModulePosition("energy", nextBuild.energy, nextBuild.body),
        rotation: 0,
      },
    ]);
    setSelectedModule(null);
    setBeamOn(false);
    setMessage(`Surprise mix: ${ufoBuildSummary(nextBuild)}.`);
    playKidSound("pop");
  };

  const saveBuild = () => {
    if (savedCurrentBuild) {
      setMessage("That build is already in your hangar.");
      playKidSound("boop");
      return;
    }
    setSavedBuilds((current) => [...current.slice(-2), { key: buildKey, label: buildSummary }]);
    setMessage(`Saved: ${buildSummary}. Build another one.`);
    playKidSound("chime");
  };

  const reset = () => {
    setBuild(DEFAULT_UFO_BUILD);
    setPartPositions({});
    setEnergyModules([]);
    setSelectedModule(null);
    setSavedBuilds([]);
    setBeamOn(false);
    setMessage("Tap one module for each socket. Watch it snap onto the lab UFO.");
    playKidSound("pop");
  };

  return (
    <section className="ufo-builder-level" aria-label="UFO builder game">
      <Starfield count={260} />
      <button className="planet-sort-back" onClick={onExit}>
        ← Back to planets
      </button>
      <div className="ufo-builder-shell">
        <div className="ufo-builder-copy">
          <span>UFO Builder</span>
          <h1>Build it piece by piece.</h1>
          <p>Click to snap parts on, or drag a module onto the lab pad.</p>
          <div className="ufo-builder-message" role="status" aria-live="polite">
            <strong>{message}</strong>
            <span>{buildSummary}</span>
          </div>
          <div className="ufo-flight-check" aria-label="UFO flight check">
            {flightChecks.map((check) => (
              <span key={check.id} className={check.ready ? "ready" : ""}>
                <em>{check.ready ? "✓" : "•"}</em>
                <strong>{check.label}</strong>
                <small>{check.hint}</small>
              </span>
            ))}
          </div>
          <div className="ufo-builder-actions">
            <button onClick={materialize}>Materialize</button>
            <button onClick={surpriseBuild}>Surprise mix</button>
            <button onClick={saveBuild}>Save build</button>
            <button onClick={reset}>Start over</button>
          </div>
          <div className="ufo-piece-controls" aria-label="Selected UFO piece controls">
            <button onClick={() => rotateSelected(-15)} disabled={!selectedModule}>
              Rotate left
            </button>
            <button onClick={() => rotateSelected(15)} disabled={!selectedModule}>
              Rotate right
            </button>
            <button onClick={removeSelected} disabled={!selectedModule}>
              Unplug
            </button>
            <button onClick={() => setSelectedModule(null)} disabled={!selectedModule}>
              Unselect
            </button>
          </div>
          {savedBuilds.length ? (
            <div className="ufo-saved-builds" aria-label="Saved UFO builds">
              <span>Hangar</span>
              {savedBuilds.map((item) => (
                <small key={item.key}>{item.label}</small>
              ))}
            </div>
          ) : null}
        </div>

        <div
          ref={stageRef}
          className={`ufo-builder-stage ${beamOn ? "beaming" : ""}`}
          aria-label="UFO assembly pad"
          onDragOver={(event) => event.preventDefault()}
          onDrop={dropPart}
        >
          <SafeAssetImage
            className="ufo-lab-bg"
            src={UFO_LAB_ART.stage}
            alt=""
            context="UfoBuilder:stage"
            fallbackText=""
          />
          <div className="ufo-light-burst" />
          <div className="ufo-spark-trail" />
          <div
            ref={craftRef}
            className={`ufo-craft generated-preview body-${build.body} windows-${build.windows} launcher-${build.launcher} energy-${build.energy}`}
          >
            <div className="ufo-generated-preview-art">
              {build.body === "angelRings" ? (
                <div className="ufo-angel-ring-sequence" aria-hidden="true">
                  <SafeAssetImage
                    className="ufo-stage-piece ufo-chassis ufo-angel-ring-frame"
                    src={UFO_ANGEL_RING_FRAMES[0]}
                    alt=""
                    context="UfoBuilder:angelRingsSmoothFrame"
                    fallbackText=""
                  />
                  <span className="ufo-angel-orbit orbit-one" />
                  <span className="ufo-angel-orbit orbit-two" />
                  <span className="ufo-angel-orbit orbit-three" />
                </div>
              ) : (
                <SafeAssetImage
                  className="ufo-stage-piece ufo-chassis"
                  src={UFO_LAB_ART.body[build.body] || UFO_LAB_ART.body.bronzeHull}
                  alt=""
                  context="UfoBuilder:chassis"
                  fallbackText=""
                />
              )}
              {UFO_BUILDER_GROUPS.map((group) => {
                if (group.id === "body" || group.id === "energy") return null;
                const partId = build[group.id];
                if (!partId) return null;
                const option = ufoOptionFor(group.id, partId);
                const position =
                  partPositions[group.id] ||
                  defaultUfoModulePosition(group.id, partId, build.body);
                const selected =
                  selectedModule?.type === "single" && selectedModule.groupId === group.id;
                return (
                  <SafeAssetImage
                    key={group.id}
                    className={`ufo-stage-piece ufo-stage-module stage-${group.id} art-${partId} ${
                      selected ? "selected-module" : ""
                    }`}
                    src={UFO_PART_ART[partId]}
                    alt=""
                    context={`UfoBuilder:${partId}`}
                    fallbackText=""
                    draggable="true"
                    role="button"
                    tabIndex="0"
                    onPointerDown={(event) =>
                      beginPointerDrag(event, group, option, {
                        type: "single",
                        groupId: group.id,
                      })
                    }
                    onClick={(event) => {
                      if (suppressNextClickRef.current) {
                        event.preventDefault();
                        return;
                      }
                      setSelectedModule({ type: "single", groupId: group.id });
                    }}
                    onKeyDown={(event) => {
                      if (event.key === "Enter" || event.key === " ") {
                        event.preventDefault();
                        setSelectedModule({ type: "single", groupId: group.id });
                      }
                    }}
                    onDragStart={(event) => dragPartData(event, group, option)}
                    style={{
                      left: `${position.x}%`,
                      top: `${position.y}%`,
                      transform: `translate(-50%, -50%) rotate(${position.rotation || 0}deg)`,
                    }}
                  />
                );
              })}
              {energyModules.map((module) => {
                const selected =
                  selectedModule?.type === "energy" && selectedModule.id === module.id;
                return (
                  <SafeAssetImage
                    key={module.id}
                    className={`ufo-stage-piece ufo-stage-module stage-energy art-${module.partId} ${
                      selected ? "selected-module" : ""
                    }`}
                    src={UFO_PART_ART[module.partId]}
                    alt=""
                    context={`UfoBuilder:${module.partId}`}
                    fallbackText=""
                    draggable="true"
                    role="button"
                    tabIndex="0"
                    onPointerDown={(event) =>
                      beginPointerDrag(
                        event,
                        UFO_BUILDER_GROUPS.find((item) => item.id === "energy"),
                        ufoOptionFor("energy", module.partId),
                        { type: "energy", id: module.id },
                      )
                    }
                    onClick={(event) => {
                      if (suppressNextClickRef.current) {
                        event.preventDefault();
                        return;
                      }
                      setSelectedModule({ type: "energy", id: module.id });
                    }}
                    onKeyDown={(event) => {
                      if (event.key === "Enter" || event.key === " ") {
                        event.preventDefault();
                        setSelectedModule({ type: "energy", id: module.id });
                      }
                    }}
                    onDragStart={(event) =>
                      dragPartData(event, UFO_BUILDER_GROUPS.find((item) => item.id === "energy"), ufoOptionFor("energy", module.partId))
                    }
                    style={{
                      left: `${module.x}%`,
                      top: `${module.y}%`,
                      transform: `translate(-50%, -50%) rotate(${module.rotation || 0}deg)`,
                    }}
                  />
                );
              })}
            </div>
          </div>
        </div>

        <div className="ufo-part-grid" aria-label="UFO parts">
          {UFO_BUILDER_GROUPS.map((group) => (
            <div className="ufo-part-group" key={group.id}>
              <h2>{group.label}</h2>
              <div className="ufo-part-options">
                {group.options.map((part) => {
                  const selected =
                    group.id === "energy"
                      ? energyModules.some((item) => item.partId === part.id)
                      : build[group.id] === part.id;
                  return (
                    <button
                      key={part.id}
                      className={`ufo-part-card ${selected ? "selected" : ""}`}
                      onClick={(event) => {
                        if (suppressNextClickRef.current) {
                          event.preventDefault();
                          return;
                        }
                        selectPart(group, part);
                      }}
                      draggable="true"
                      onPointerDown={(event) => beginPointerDrag(event, group, part)}
                      onDragStart={(event) => dragPartData(event, group, part)}
                      aria-pressed={selected ? "true" : "false"}
                    >
                      <SafeAssetImage
                        className={`ufo-art-icon art-${part.id}`}
                        src={UFO_PART_ART[part.id]}
                        alt=""
                        context={`UfoBuilderCard:${part.id}`}
                        fallbackText=""
                      />
                      <strong>{part.label}</strong>
                      <small>{part.cue}</small>
                    </button>
                  );
                })}
              </div>
            </div>
          ))}
        </div>
        {dragPreview ? (
          <div
            className={`ufo-drag-preview ${dragPreview.overPad ? "over-pad" : ""}`}
            style={{
              left: `${dragPreview.x}px`,
              top: `${dragPreview.y}px`,
            }}
            aria-hidden="true"
          >
            <SafeAssetImage
              className={`ufo-drag-preview-art art-${dragPreview.partId}`}
              src={dragPreview.src}
              alt=""
              context={`UfoBuilderDrag:${dragPreview.partId}`}
              fallbackText=""
            />
            <span>{dragPreview.overPad ? "Release to place" : dragPreview.label}</span>
          </div>
        ) : null}
      </div>
    </section>
  );
}
