import { useRef, useState, useEffect, forwardRef } from 'react';
import { useFrame, useThree } from '@react-three/fiber';
import { useXRInputSourceState, useXR } from '@react-three/xr';
import { useNavigate } from 'react-router-dom';
import * as THREE from 'three';
import { Text } from '@react-three/drei';
import { XR3DButton, XR3DPanel } from './XRPanel3D';
import { useModelStore, SCALE_PRESETS } from '@/stores/useModelStore';
import { getBroadcastSource } from '@/lib/webrtc/broadcastSource';
import {
  useCanvasRecorder, startRecording, pauseRecording, resumeRecording,
  stopRecording, captureScreenshot, formatElapsed,
} from '@/hooks/useCanvasRecorder';
import { getAllModelLocalGroups } from '@/lib/modelTransforms';
import { toast } from 'sonner';
import {
  xrCalibration,
  startXRCalibration,
  cancelXRCalibration,
  subscribeXRCalibration,
} from './xrCalibrationBus';
import { XRViewCube } from './XRViewCube';

type Tab = 'scene' | 'tools' | 'calib' | 'cuts' | 'inspection' | 'share' | 'capture' | 'webxr';

interface XRHudInWorldProps {
  freeMove: boolean;
  onToggleFreeMove: () => void;
  placementMode: boolean;
  onTogglePlacement: () => void;
  snapToPlanes: boolean;
  onToggleSnap: () => void;
  allowScale: boolean;
  onToggleAllowScale: () => void;
  liveCode?: string | null;
  liveViewers?: number;
  onStartLive?: () => void;
  onStopLive?: () => void;
}

const POS_STEP = 0.001;
const ROT_STEP = 1;
const SCALE_LABELS = ['1:50', '1:20', '1:10', '1:1'];

const WristToggle = forwardRef<THREE.Group, { open: boolean; onToggle: () => void }>(
  function WristToggle({ open, onToggle }, ref) {
    return (
      <group ref={ref}>
        <mesh position={[0, 0, -0.0005]}>
          <planeGeometry args={[0.064, 0.032]} />
          <meshBasicMaterial color="#3b82f6" transparent opacity={0.6} />
        </mesh>
        <mesh onClick={(e) => { e.stopPropagation(); onToggle(); }}>
          <planeGeometry args={[0.06, 0.028]} />
          <meshBasicMaterial color={open ? '#3b82f6' : '#1a1a1a'} transparent opacity={0.95} />
        </mesh>
        <Text position={[0, 0, 0.001]} fontSize={0.0085} color="#ffffff" anchorX="center" anchorY="middle">
          {open ? '✕ Fechar' : '☰ Menu'}
        </Text>
      </group>
    );
  },
);

export function XRHudInWorld(props: XRHudInWorldProps) {
  const { camera } = useThree();
  const leftCtrl = useXRInputSourceState('controller', 'left');
  const rightCtrl = useXRInputSourceState('controller', 'right');
  const xrSession = useXR((s) => s.session);
  const navigate = useNavigate();
  const [open, setOpen] = useState(true);
  /** Visibility of the small head-locked floating button group (toggled by X button). */
  const [hudVisible, setHudVisible] = useState(true);
  const [tab, setTab] = useState<Tab>('scene');
  /** When pinned, the panel stays fixed in world space and does NOT follow the head. */
  const [pinned, setPinned] = useState(true);
  /** While true, the panel is glued to the right controller (drag mode). */
  const [dragging, setDragging] = useState(false);
  /** Forces re-anchor on next frame (used by "trazer" / unpin→pin). */
  const reanchorRequested = useRef(true);

  const panelRef = useRef<THREE.Group>(null);
  const wristRef = useRef<THREE.Group>(null);
  const headLockRef = useRef<THREE.Group>(null);
  const targetPos = useRef(new THREE.Vector3());
  const targetQuat = useRef(new THREE.Quaternion());
  const lastButtonsState = useRef({
    left4: false, // X
    left5: false, // Y
    left3: false, // Menu (☰)
    right4: false, // A
    right5: false, // B
  });
  /** Cached offset from controller to panel at drag start. */
  const dragOffsetPos = useRef(new THREE.Vector3());
  const dragOffsetQuat = useRef(new THREE.Quaternion());
  const dragInitialized = useRef(false);

  useFrame(() => {
    // Escuta botões A, B, X, Y e Menu do esquerdo
    const gpLeft = leftCtrl?.inputSource?.gamepad;
    const gpRight = rightCtrl?.inputSource?.gamepad;

    let xPressed = false;
    let yPressed = false;
    let menuPressed = false;
    let aPressed = false;
    let bPressed = false;

    if (gpLeft) {
      // Esquerdo: Menu (3), X (4), Y (5)
      const btnMenu = gpLeft.buttons[3];
      const btnX = gpLeft.buttons[4];
      const btnY = gpLeft.buttons[5];

      if (btnX?.pressed && !lastButtonsState.current.left4) xPressed = true;
      if (btnY?.pressed && !lastButtonsState.current.left5) yPressed = true;
      if (btnMenu?.pressed && !lastButtonsState.current.left3) menuPressed = true;

      lastButtonsState.current.left4 = !!btnX?.pressed;
      lastButtonsState.current.left5 = !!btnY?.pressed;
      lastButtonsState.current.left3 = !!btnMenu?.pressed;
    }

    if (gpRight) {
      // Direito: A (4), B (5)
      const btnA = gpRight.buttons[4];
      const btnB = gpRight.buttons[5];

      if (btnA?.pressed && !lastButtonsState.current.right4) aPressed = true;
      if (btnB?.pressed && !lastButtonsState.current.right5) bPressed = true;

      lastButtonsState.current.right4 = !!btnA?.pressed;
      lastButtonsState.current.right5 = !!btnB?.pressed;
    }

    // Se o menu estiver aberto, pressionar X físico fecha o projeto (encerra sessão AR)
    if (xPressed && open) {
      try { xrSession?.end(); } catch (e) { console.warn('[XR] session.end failed', e); }
      setTimeout(() => navigate('/viewer'), 50);
      toast.success("Projeto fechado!");
    } else if (aPressed || bPressed || xPressed || yPressed) {
      // Se qualquer um dos botões A, B, X, Y for pressionado, abre/traz o menu
      setOpen(true);
      reanchorRequested.current = true;
    }

    // Pressionar o botão de Menu (☰) do controle esquerdo abre o menu de ferramentas diretamente
    if (menuPressed) {
      setOpen(true);
      setTab('tools');
      reanchorRequested.current = true;
    }

    // Floating panel:
    //  • If pinned and already anchored once → don't move it (fixed in space).
    //  • If unpinned → continuously follow head with damping.
    //  • On (re)anchor request → snap target once and stop.
    if (panelRef.current && open) {
      // Drag mode → panel rigidly follows right controller using captured offset.
      if (dragging) {
        const ctrlObj = rightCtrl?.object;
        if (ctrlObj) {
          ctrlObj.updateMatrixWorld();
          const cPos = new THREE.Vector3().setFromMatrixPosition(ctrlObj.matrixWorld);
          const cQuat = new THREE.Quaternion().setFromRotationMatrix(ctrlObj.matrixWorld);
          if (!dragInitialized.current) {
            // Capture current panel pose relative to controller
            const invQ = cQuat.clone().invert();
            dragOffsetPos.current
              .copy(panelRef.current.position).sub(cPos).applyQuaternion(invQ);
            dragOffsetQuat.current.copy(invQ).multiply(panelRef.current.quaternion);
            dragInitialized.current = true;
          }
          const newPos = dragOffsetPos.current.clone().applyQuaternion(cQuat).add(cPos);
          const newQuat = cQuat.clone().multiply(dragOffsetQuat.current);
          panelRef.current.position.copy(newPos);
          panelRef.current.quaternion.copy(newQuat);
        }
      } else {
        if (dragInitialized.current) dragInitialized.current = false;
        const fwd = new THREE.Vector3(0, -0.05, -0.7).applyQuaternion(camera.quaternion);
        const wantPos = new THREE.Vector3().copy(camera.position).add(fwd);
        const euler = new THREE.Euler().setFromQuaternion(camera.quaternion, 'YXZ');
        const wantQuat = new THREE.Quaternion().setFromEuler(new THREE.Euler(0, euler.y, 0, 'YXZ'));

        if (reanchorRequested.current) {
          targetPos.current.copy(wantPos);
          targetQuat.current.copy(wantQuat);
          panelRef.current.position.copy(wantPos);
          panelRef.current.quaternion.copy(wantQuat);
          reanchorRequested.current = false;
        } else if (!pinned) {
          targetPos.current.copy(wantPos);
          targetQuat.current.copy(wantQuat);
          panelRef.current.position.lerp(targetPos.current, 0.12);
          panelRef.current.quaternion.slerp(targetQuat.current, 0.18);
        }
        // pinned + already anchored → leave panel where it is.
      }
    }

    // Wrist toggle follows left controller
    if (wristRef.current) {
      const ctrlObj = leftCtrl?.object;
      if (ctrlObj) {
        ctrlObj.updateMatrixWorld();
        const p = new THREE.Vector3().setFromMatrixPosition(ctrlObj.matrixWorld);
        const q = new THREE.Quaternion().setFromRotationMatrix(ctrlObj.matrixWorld);
        const offset = new THREE.Vector3(0, 0.06, 0.02).applyQuaternion(q);
        wristRef.current.position.copy(p).add(offset);
        wristRef.current.quaternion.copy(q);
        wristRef.current.visible = true;
      } else {
        wristRef.current.visible = false;
      }
    }

    // Head-locked fallback toggle — always visible in lower-left of FOV,
    // so the user can reopen the menu even without controllers or if the
    // panel is positioned out of view.
    if (headLockRef.current) {
      const offset = new THREE.Vector3(-0.18, -0.18, -0.5).applyQuaternion(camera.quaternion);
      headLockRef.current.position.copy(camera.position).add(offset);
      headLockRef.current.quaternion.copy(camera.quaternion);
    }
  });

  const showGrid = useModelStore((s) => s.showGrid);
  const setShowGrid = useModelStore((s) => s.setShowGrid);

  return (
    <>
      <WristToggle ref={wristRef} open={open} onToggle={() => setOpen((v) => !v)} />
      {/* Head-locked fallback: floating quick-controls in lower-left of FOV.
          Toggled on/off by the left controller X button. */}
      <group ref={headLockRef} renderOrder={999} visible={hudVisible}>
        <XR3DButton position={[0, 0.030, 0]} size={[0.07, 0.022]}
          label={open ? '✕ Menu' : '☰ Menu'} active={open}
          onClick={() => { setOpen((v) => !v); reanchorRequested.current = true; }}
          fontSize={0.0085} />
        <XR3DButton position={[0, 0.004, 0]} size={[0.07, 0.022]}
          label={showGrid ? 'Grid ON' : 'Grid OFF'} active={showGrid}
          onClick={() => setShowGrid(!showGrid)} fontSize={0.0085} />
        <XR3DButton position={[0, -0.022, 0]} size={[0.07, 0.022]}
          label="⏏ Sair AR"
          onClick={() => {
            // End the XR session while preserving placement/state in the store,
            // then return to the Viewer. Re-entering AR restores the same state.
            try { xrSession?.end(); } catch (e) { console.warn('[XR] session.end failed', e); }
            setTimeout(() => navigate('/viewer'), 50);
          }}
          fontSize={0.0085} />
        <RecIndicator />
      </group>
      {open && (
        <group ref={panelRef}>
          <FloatingPanel
            tab={tab}
            setTab={setTab}
            pinned={pinned}
            onTogglePin={() => setPinned((v) => !v)}
            dragging={dragging}
            onToggleDrag={() => setDragging((v) => !v)}
            onRecenter={() => { reanchorRequested.current = true; }}
            {...props}
          />
        </group>
      )}
    </>
  );
}

function FloatingPanel({
  tab, setTab, pinned, onTogglePin, dragging, onToggleDrag, onRecenter, ...p
}: {
  tab: Tab;
  setTab: (t: Tab) => void;
  pinned: boolean;
  onTogglePin: () => void;
  dragging: boolean;
  onToggleDrag: () => void;
  onRecenter: () => void;
} & XRHudInWorldProps) {
  const tabs: { id: Tab; label: string; icon: string }[] = [
    { id: 'scene', label: 'Cena', icon: '🧩' },
    { id: 'tools', label: 'Ferram.', icon: '🛠' },
    { id: 'calib', label: 'Calibrar', icon: '🎯' },
    { id: 'cuts', label: 'Cortes', icon: '✂' },
    { id: 'inspection', label: 'Inspeção', icon: '✓' },
    { id: 'capture', label: 'Captura', icon: '🎥' },
    { id: 'share', label: 'Compart.', icon: '📡' },
    { id: 'webxr', label: 'WebXR', icon: '⚙' },
  ];
  const W = 0.54, H = 0.38;
  return (
    <XR3DPanel size={[W, H]}>
      <Text position={[-W / 2 + 0.012, H / 2 - 0.018, 0.002]} fontSize={0.011} color="#3b82f6"
            anchorX="left" anchorY="middle">
        SteelXR · HUD AR
      </Text>
      {/* Pin / Drag / Recenter — anchored to top-right, kept inside the panel.
          Group origin is at the right edge with margin; buttons extend leftward. */}
      <group position={[W / 2 - 0.008, H / 2 - 0.018, 0.002]}>
        {/* Trazer (recenter) — rightmost, half-width 0.029 from origin */}
        <XR3DButton position={[-0.029, 0, 0]} size={[0.054, 0.022]}
          label="⎚ Trazer" onClick={onRecenter} fontSize={0.007} />
        {/* Mover (drag with right controller) */}
        <XR3DButton position={[-0.088, 0, 0]} size={[0.054, 0.022]}
          label={dragging ? '✋ Solte' : '✋ Mover'}
          active={dragging} onClick={onToggleDrag} fontSize={0.007} />
        {/* Pin */}
        <XR3DButton position={[-0.144, 0, 0]} size={[0.054, 0.022]}
          label={pinned ? '📌 Fixo' : '↻ Solto'}
          active={pinned} onClick={onTogglePin} fontSize={0.007} />
      </group>

      <group position={[0, H / 2 - 0.045, 0.001]}>
        {tabs.map((t, i) => (
          <XR3DButton key={t.id}
            position={[-W / 2 + 0.0495 + i * 0.063, 0, 0]} size={[0.058, 0.020]}
            label={t.label} icon={t.icon} active={tab === t.id}
            onClick={() => setTab(t.id)} fontSize={0.0062} />
        ))}
      </group>

      <group position={[0, -0.018, 0.001]}>
        {tab === 'scene' && <SceneTab />}
        {tab === 'tools' && <ToolsTab {...p} />}
        {tab === 'calib' && <CalibrationTab />}
        {tab === 'cuts' && <CutsTab />}
        {tab === 'inspection' && <InspectionTab />}
        {tab === 'capture' && <CaptureTab />}
        {tab === 'share' && <ShareTab {...p} />}
        {tab === 'webxr' && <WebXRTab />}
      </group>
    </XR3DPanel>
  );
}

interface AxisRange { min: number; max: number; }
type Axis = 'x' | 'y' | 'z';

function computeBoundsByAxis(): Record<Axis, AxisRange> | null {
  const groups = getAllModelLocalGroups();
  if (groups.length === 0) return null;
  const box = new THREE.Box3();
  let has = false;
  for (const g of groups) {
    g.updateWorldMatrix(true, true);
    const b = new THREE.Box3().setFromObject(g);
    if (Number.isFinite(b.min.x) && Number.isFinite(b.max.x)) {
      if (!has) { box.copy(b); has = true; } else box.union(b);
    }
  }
  if (!has) return null;
  return {
    x: { min: box.min.x, max: box.max.x },
    y: { min: box.min.y, max: box.max.y },
    z: { min: box.min.z, max: box.max.z },
  };
}

const AXIS_COLOR: Record<Axis, string> = {
  x: '#ef4444',
  y: '#10b981',
  z: '#0ea5e9',
};

const AXIS_LABEL: Record<Axis, string> = { x: 'X', y: 'Y', z: 'Z' };

function CutsTab() {
  const enabled = useModelStore((s) => s.sectionEnabled);
  const invert = useModelStore((s) => s.sectionInvert);
  const level = useModelStore((s) => s.sectionLevel);
  const setSectionEnabled = useModelStore((s) => s.setSectionEnabled);
  const setSectionInvert = useModelStore((s) => s.setSectionInvert);
  const setSectionLevel = useModelStore((s) => s.setSectionLevel);
  const activeModelId = useModelStore((s) => s.activeModelId);

  const [bounds, setBounds] = useState<Record<Axis, AxisRange> | null>(null);
  const [step, setStep] = useState<number>(0.01); // 10mm por padrão

  useEffect(() => {
    setBounds(computeBoundsByAxis());
  }, [activeModelId]);

  const handleStepChange = (sVal: number) => {
    setStep(sVal);
  };

  const handleAdjust = (axis: Axis, dir: 1 | -1) => {
    const range = bounds?.[axis];
    if (!range) return;
    const currentVal = level[axis];
    const newVal = Math.max(range.min, Math.min(range.max, currentVal + dir * step));
    setSectionLevel(axis, newVal);
  };

  const handleSetPreset = (axis: Axis, type: 'min' | 'center' | 'max') => {
    const range = bounds?.[axis];
    if (!range) return;
    if (type === 'min') {
      setSectionLevel(axis, range.min);
    } else if (type === 'center') {
      setSectionLevel(axis, (range.min + range.max) / 2);
    } else if (type === 'max') {
      setSectionLevel(axis, range.max);
    }
  };

  const handleRecalculate = () => {
    setBounds(computeBoundsByAxis());
  };

  return (
    <group>
      {/* Cabeçalho / Passo */}
      <Text position={[-0.24, 0.115, 0]} fontSize={0.0085} color="#94a3b8" anchorX="left" anchorY="middle">
        Passo do Ajuste:
      </Text>
      <XR3DButton position={[-0.09, 0.115, 0]} size={[0.048, 0.02]}
        label="1 mm" active={step === 0.001} onClick={() => handleStepChange(0.001)} fontSize={0.007} />
      <XR3DButton position={[-0.038, 0.115, 0]} size={[0.048, 0.02]}
        label="10 mm" active={step === 0.01} onClick={() => handleStepChange(0.01)} fontSize={0.007} />
      <XR3DButton position={[0.014, 0.115, 0]} size={[0.048, 0.02]}
        label="50 mm" active={step === 0.05} onClick={() => handleStepChange(0.05)} fontSize={0.007} />

      <XR3DButton position={[0.165, 0.115, 0]} size={[0.12, 0.02]}
        label="↺ Recalcular Limites" active={false} onClick={handleRecalculate} fontSize={0.007} />

      {/* Controles dos Eixos */}
      {(['x', 'y', 'z'] as Axis[]).map((axis, idx) => {
        const yOffset = 0.055 - idx * 0.055;
        const range = bounds?.[axis];
        const minMM = range ? range.min * 1000 : 0;
        const maxMM = range ? range.max * 1000 : 100;
        const valMM = level[axis] * 1000;
        const isAxisEnabled = enabled[axis];
        const isAxisInverted = invert[axis];
        const isAxisDisabled = !range;

        return (
          <group key={axis} position={[0, yOffset, 0]}>
            {/* Eixo label */}
            <Text position={[-0.24, 0, 0]} fontSize={0.014} color={AXIS_COLOR[axis]} anchorX="left" anchorY="middle">
              {AXIS_LABEL[axis]}
            </Text>

            {/* Toggle Cortar */}
            <XR3DButton position={[-0.19, 0, 0]} size={[0.045, 0.022]}
              label={isAxisEnabled ? "ON" : "OFF"} active={isAxisEnabled}
              disabled={isAxisDisabled}
              onClick={() => setSectionEnabled(axis, !isAxisEnabled)}
              fontSize={0.0075} />

            {/* Toggle Inverter */}
            <XR3DButton position={[-0.135, 0, 0]} size={[0.052, 0.022]}
              label={isAxisInverted ? "Invertido" : "Inverter"} active={isAxisInverted}
              disabled={isAxisDisabled || !isAxisEnabled}
              onClick={() => setSectionInvert(axis, !isAxisInverted)}
              fontSize={0.007} />

            {/* Valor */}
            <Text position={[-0.09, 0, 0]} fontSize={0.0085} color={isAxisEnabled ? "#ffffff" : "#64748b"} anchorX="left" anchorY="middle">
              {isAxisDisabled ? "sem peça" : `${valMM.toFixed(1)} mm`}
            </Text>

            {/* Menos/Mais */}
            <XR3DButton position={[0.01, 0, 0]} size={[0.024, 0.022]}
              label="−" disabled={isAxisDisabled || !isAxisEnabled}
              onClick={() => handleAdjust(axis, -1)}
              fontSize={0.01} />
            <XR3DButton position={[0.038, 0, 0]} size={[0.024, 0.022]}
              label="+" disabled={isAxisDisabled || !isAxisEnabled}
              onClick={() => handleAdjust(axis, 1)}
              fontSize={0.01} />

            {/* Presets */}
            <XR3DButton position={[0.076, 0, 0]} size={[0.034, 0.022]}
              label="Min" disabled={isAxisDisabled || !isAxisEnabled}
              onClick={() => handleSetPreset(axis, 'min')}
              fontSize={0.007} />
            <XR3DButton position={[0.118, 0, 0]} size={[0.042, 0.022]}
              label="Centro" disabled={isAxisDisabled || !isAxisEnabled}
              onClick={() => handleSetPreset(axis, 'center')}
              fontSize={0.007} />
            <XR3DButton position={[0.162, 0, 0]} size={[0.036, 0.022]}
              label="Max" disabled={isAxisDisabled || !isAxisEnabled}
              onClick={() => handleSetPreset(axis, 'max')}
              fontSize={0.007} />
          </group>
        );
      })}
    </group>
  );
}

function SceneTab() {
  const models = useModelStore((s) => s.models);
  const activeId = useModelStore((s) => s.activeModelId);
  const setActive = useModelStore((s) => s.setActiveModel);
  const toggleVisible = useModelStore((s) => s.toggleModelVisible);
  const toggleLocked = useModelStore((s) => s.toggleModelLocked);
  const remove = useModelStore((s) => s.removeModel);
  const duplicate = useModelStore((s) => s.duplicateModel);

  if (models.length === 0) {
    return (
      <Text fontSize={0.011} color="#94a3b8" anchorX="center" anchorY="middle" maxWidth={0.45}>
        Nenhuma peça na cena. Saia do AR para carregar arquivos no Viewer.
      </Text>
    );
  }

  return (
    <group>
      <Text position={[-0.24, 0.11, 0]} fontSize={0.008} color="#94a3b8" anchorX="left">
        Toque no nome para tornar a peça ativa
      </Text>
      {models.slice(0, 5).map((m, i) => {
        const y = 0.085 - i * 0.04;
        const isActive = m.id === activeId;
        return (
          <group key={m.id} position={[0, y, 0]}>
            <mesh position={[-0.235, 0, 0.001]}>
              <circleGeometry args={[0.005, 16]} />
              <meshBasicMaterial color={m.color} />
            </mesh>
            <group onClick={(e) => { e.stopPropagation(); setActive(m.id); }}>
              <mesh position={[-0.11, 0, 0]}>
                <planeGeometry args={[0.22, 0.026]} />
                <meshBasicMaterial color={isActive ? '#1e3a8a' : '#1a1a1a'} transparent opacity={0.85} />
              </mesh>
              <Text position={[-0.215, 0, 0.001]} fontSize={0.0085}
                    color={isActive ? '#ffffff' : '#cbd5e1'} anchorX="left" anchorY="middle"
                    maxWidth={0.2}>
                {m.fileName}
              </Text>
            </group>
            <XR3DButton position={[0.04, 0, 0]} size={[0.04, 0.024]}
              label={m.visible ? '👁' : '⊘'} fontSize={0.012}
              onClick={() => toggleVisible(m.id)} />
            <XR3DButton position={[0.085, 0, 0]} size={[0.04, 0.024]}
              label={m.locked ? '🔒' : '🔓'} fontSize={0.012}
              onClick={() => toggleLocked(m.id)} />
            <XR3DButton position={[0.13, 0, 0]} size={[0.04, 0.024]}
              label="⎘" fontSize={0.012}
              onClick={() => duplicate(m.id)} />
            <XR3DButton position={[0.175, 0, 0]} size={[0.04, 0.024]}
              label="✕" fontSize={0.012} color="#dc2626"
              onClick={() => remove(m.id)} />
          </group>
        );
      })}
    </group>
  );
}

function ToolsTab(p: XRHudInWorldProps) {
  const opacity = useModelStore((s) => s.opacity);
  const setOpacity = useModelStore((s) => s.setOpacity);
  const renderMode = useModelStore((s) => s.renderMode);
  const setRenderMode = useModelStore((s) => s.setRenderMode);
  const showGrid = useModelStore((s) => s.showGrid);
  const setShowGrid = useModelStore((s) => s.setShowGrid);
  const measureMode = useModelStore((s) => s.measureMode);
  const setMeasureMode = useModelStore((s) => s.setMeasureMode);
  const selectionMode = useModelStore((s) => s.selectionMode);
  const setSelectionMode = useModelStore((s) => s.setSelectionMode);
  const selectedCount = useModelStore((s) => s.selectedElementKeys.size);
  const hideSelectedElements = useModelStore((s) => s.hideSelectedElements);
  const isolateSelectedElements = useModelStore((s) => s.isolateSelectedElements);
  const showAllElements = useModelStore((s) => s.showAllElements);
  const hasHidden = useModelStore((s) =>
    s.hiddenElementKeys.size > 0 || s.isolatedElementKeys !== null
  );
  const scaleRatio = useModelStore((s) => s.scaleRatio);
  const setScaleRatio = useModelStore((s) => s.setScaleRatio);
  const resetScale = useModelStore((s) => s.resetScale);
  const clearMeasurements = useModelStore((s) => s.clearMeasurements);
  const undoLastMeasurement = useModelStore((s) => s.undoLastMeasurement);

  return (
    <group>
      <Text position={[-0.24, 0.11, 0]} fontSize={0.008} color="#94a3b8" anchorX="left">Render</Text>
      <XR3DButton position={[-0.16, 0.085, 0]} size={[0.075, 0.022]} label="Sólido"
        active={renderMode === 'solid'} onClick={() => setRenderMode('solid')} />
      <XR3DButton position={[-0.08, 0.085, 0]} size={[0.075, 0.022]} label="Wire"
        active={renderMode === 'wireframe'} onClick={() => setRenderMode('wireframe')} />
      <XR3DButton position={[0.0, 0.085, 0]} size={[0.075, 0.022]} label="Bordas"
        active={renderMode === 'edges'} onClick={() => setRenderMode('edges')} />

      <Text position={[-0.24, 0.05, 0]} fontSize={0.008} color="#94a3b8" anchorX="left">Toggles</Text>
      <XR3DButton position={[-0.16, 0.025, 0]} size={[0.075, 0.022]} label={`Grid ${showGrid ? 'ON' : 'OFF'}`}
        active={showGrid} onClick={() => setShowGrid(!showGrid)} />
      <XR3DButton position={[-0.08, 0.025, 0]} size={[0.075, 0.022]} label={`Medir ${measureMode ? 'ON' : 'OFF'}`}
        active={measureMode} onClick={() => setMeasureMode(!measureMode)} />
      <XR3DButton position={[0.0, 0.025, 0]} size={[0.075, 0.022]} label={`Snap ${p.snapToPlanes ? 'ON' : 'OFF'}`}
        active={p.snapToPlanes} onClick={p.onToggleSnap} />
      <XR3DButton position={[0.08, 0.025, 0]} size={[0.075, 0.022]}
        label={p.placementMode ? 'Posic…' : 'Reposic.'}
        active={p.placementMode} onClick={p.onTogglePlacement} />
      <XR3DButton position={[0.16, 0.025, 0]} size={[0.075, 0.022]}
        label={`Zoom ${p.allowScale ? 'ON' : 'OFF'}`}
        active={p.allowScale} onClick={p.onToggleAllowScale} />

      {/* Selecionar — paridade com a tela inicial */}
      <Text position={[-0.24, -0.005, 0]} fontSize={0.008} color="#94a3b8" anchorX="left">Selecionar</Text>
      <XR3DButton position={[-0.16, -0.03, 0]} size={[0.075, 0.022]}
        label={selectionMode ? (selectedCount > 0 ? `${selectedCount} sel.` : 'Selec…') : 'Selec'}
        active={selectionMode} onClick={() => setSelectionMode(!selectionMode)} />
      <XR3DButton position={[-0.08, -0.03, 0]} size={[0.075, 0.022]} label="Esconder"
        onClick={hideSelectedElements} />
      <XR3DButton position={[0.0, -0.03, 0]} size={[0.075, 0.022]} label="Isolar"
        onClick={isolateSelectedElements} />
      <XR3DButton position={[0.08, -0.03, 0]} size={[0.075, 0.022]} label="Mostrar"
        active={hasHidden} onClick={showAllElements} />

      <Text position={[-0.24, -0.06, 0]} fontSize={0.008} color="#94a3b8" anchorX="left">
        Opacidade {Math.round(opacity * 100)}%
      </Text>
      <XR3DButton position={[-0.16, -0.085, 0]} size={[0.05, 0.022]} label="−25%"
        onClick={() => setOpacity(Math.max(0, opacity - 0.25))} />
      <XR3DButton position={[-0.105, -0.085, 0]} size={[0.05, 0.022]} label="−5%"
        onClick={() => setOpacity(Math.max(0, opacity - 0.05))} />
      <XR3DButton position={[-0.05, -0.085, 0]} size={[0.05, 0.022]} label="+5%"
        onClick={() => setOpacity(Math.min(1, opacity + 0.05))} />
      <XR3DButton position={[0.005, -0.085, 0]} size={[0.05, 0.022]} label="+25%"
        onClick={() => setOpacity(Math.min(1, opacity + 0.25))} />
      <XR3DButton position={[0.06, -0.085, 0]} size={[0.05, 0.022]} label="100%"
        onClick={() => setOpacity(1)} />

      <Text position={[-0.24, -0.115, 0]} fontSize={0.008} color="#94a3b8" anchorX="left">
        Escala {scaleRatio.label}
      </Text>
      {SCALE_LABELS.map((lbl, i) => {
        const preset = SCALE_PRESETS.find((sp) => sp.label === lbl)!;
        return (
          <XR3DButton key={lbl}
            position={[-0.16 + i * 0.054, -0.14, 0]} size={[0.05, 0.022]} label={lbl}
            active={scaleRatio.label === lbl}
            onClick={() => setScaleRatio(preset)} />
        );
      })}
      <XR3DButton position={[0.076, -0.14, 0]} size={[0.046, 0.022]}
        label="↺ Reset" color="#dc2626"
        onClick={resetScale} fontSize={0.0075} />
      <XR3DButton position={[0.126, -0.14, 0]} size={[0.05, 0.022]}
        label="⎌ Desfaz" color="#3b82f6"
        onClick={undoLastMeasurement} fontSize={0.0075} />
      <XR3DButton position={[0.18, -0.14, 0]} size={[0.05, 0.022]}
        label="✕ Limpa" color="#dc2626"
        onClick={clearMeasurements} fontSize={0.0075} />

      {measureMode && (
        <Text position={[-0.24, -0.17, 0]} fontSize={0.0065} color="#a3e635" anchorX="left" maxWidth={0.5}>
          Gatilho D: marcar ponto · Gatilho E: alternar snap · A/B/X/Y: abrir Menu
        </Text>
      )}

      <GridFloorRow />
    </group>
  );
}

function GridFloorRow() {
  const { camera } = useThree();
  const gridY = useModelStore((s) => s.gridY);
  const gridAutoFollow = useModelStore((s) => s.gridAutoFollow);
  const setGridAutoFollow = useModelStore((s) => s.setGridAutoFollow);
  const setGridY = useModelStore((s) => s.setGridY);
  const nudgeGridY = useModelStore((s) => s.nudgeGridY);
  const gridCalibMode = useModelStore((s) => s.gridCalibMode);
  const setGridCalibMode = useModelStore((s) => s.setGridCalibMode);
  const gridLandingMode = useModelStore((s) => s.gridLandingMode);
  const setGridLandingMode = useModelStore((s) => s.setGridLandingMode);

  return (
    <group>
      <Text position={[-0.24, -0.15, 0]} fontSize={0.008} color="#94a3b8" anchorX="left">
        Grid Y {(gridY * 1000).toFixed(0)}mm {gridAutoFollow ? '(auto)' : '(travado)'}
      </Text>
      <XR3DButton position={[-0.16, -0.175, 0]} size={[0.055, 0.022]} label="Auto"
        active={gridAutoFollow} onClick={() => setGridAutoFollow(true)} />
      <XR3DButton position={[-0.10, -0.175, 0]} size={[0.055, 0.022]} label="Travar"
        active={!gridAutoFollow} onClick={() => setGridAutoFollow(false)} />
      <XR3DButton position={[-0.04, -0.175, 0]} size={[0.04, 0.022]} label="−1cm"
        onClick={() => nudgeGridY(-0.01)} />
      <XR3DButton position={[0.005, -0.175, 0]} size={[0.04, 0.022]} label="+1cm"
        onClick={() => nudgeGridY(0.01)} />
      <XR3DButton position={[0.07, -0.175, 0]} size={[0.075, 0.022]} label={gridLandingMode ? "Pousando" : "Pousar"}
        active={gridLandingMode} onClick={() => setGridLandingMode(!gridLandingMode)} />
      <XR3DButton position={[0.155, -0.175, 0]} size={[0.075, 0.022]} label={gridCalibMode ? "Calibrando" : "Calibrar"}
        active={gridCalibMode} onClick={() => setGridCalibMode(!gridCalibMode)} />
    </group>
  );
}

function TransformTab() {
  const fineTuning = useModelStore((s) => s.fineTuning);
  const setFineTuning = useModelStore((s) => s.setFineTuning);
  const reset = useModelStore((s) => s.resetFineTuning);

  const Row = ({
    label, axis, isRot, y,
  }: { label: string; axis: 'posX'|'posY'|'posZ'|'rotX'|'rotY'|'rotZ'; isRot: boolean; y: number }) => {
    const step = isRot ? ROT_STEP : POS_STEP;
    const val = fineTuning[axis];
    const display = isRot ? `${val.toFixed(1)}°` : `${(val * 1000).toFixed(1)}mm`;
    return (
      <group position={[0, y, 0]}>
        <Text position={[-0.235, 0, 0]} fontSize={0.009} color="#cbd5e1" anchorX="left" anchorY="middle">
          {label}
        </Text>
        <XR3DButton position={[-0.10, 0, 0]} size={[0.04, 0.024]} label="−−"
          onClick={() => setFineTuning({ [axis]: val - step * 10 })} />
        <XR3DButton position={[-0.05, 0, 0]} size={[0.04, 0.024]} label="−"
          onClick={() => setFineTuning({ [axis]: val - step })} />
        <Text position={[0.0, 0, 0]} fontSize={0.009} color="#3b82f6" anchorX="center" anchorY="middle">
          {display}
        </Text>
        <XR3DButton position={[0.05, 0, 0]} size={[0.04, 0.024]} label="+"
          onClick={() => setFineTuning({ [axis]: val + step })} />
        <XR3DButton position={[0.10, 0, 0]} size={[0.04, 0.024]} label="++"
          onClick={() => setFineTuning({ [axis]: val + step * 10 })} />
      </group>
    );
  };

  return (
    <group>
      <Row label="Pos X" axis="posX" isRot={false} y={0.105} />
      <Row label="Pos Y" axis="posY" isRot={false} y={0.075} />
      <Row label="Pos Z" axis="posZ" isRot={false} y={0.045} />
      <Row label="Rot X" axis="rotX" isRot={true} y={0.005} />
      <Row label="Rot Y" axis="rotY" isRot={true} y={-0.025} />
      <Row label="Rot Z" axis="rotZ" isRot={true} y={-0.055} />
      <XR3DButton position={[0, -0.105, 0]} size={[0.12, 0.026]} label="↺ Reset" onClick={reset} />
    </group>
  );
}

function InspectionTab() {
  const checklist = useModelStore((s) => s.checklist);
  const setStatus = useModelStore((s) => s.setChecklistItemStatus);
  return (
    <group>
      <Text position={[-0.24, 0.11, 0]} fontSize={0.008} color="#94a3b8" anchorX="left">
        Checklist de inspeção
      </Text>
      {checklist.map((item, i) => {
        const y = 0.075 - i * 0.045;
        const color = item.status === 'approved' ? '#22c55e'
          : item.status === 'rejected' ? '#dc2626' : '#94a3b8';
        return (
          <group key={item.id} position={[0, y, 0]}>
            <mesh position={[-0.235, 0, 0]}>
              <circleGeometry args={[0.005, 16]} />
              <meshBasicMaterial color={color} />
            </mesh>
            <Text position={[-0.22, 0, 0]} fontSize={0.009} color="#e5e7eb"
                  anchorX="left" anchorY="middle" maxWidth={0.18}>
              {item.label}
            </Text>
            <XR3DButton position={[0.06, 0, 0]} size={[0.05, 0.024]} label="✓ OK" color="#16a34a"
              active={item.status === 'approved'} onClick={() => setStatus(item.id, 'approved')} />
            <XR3DButton position={[0.115, 0, 0]} size={[0.05, 0.024]} label="✗ NOK" color="#dc2626"
              active={item.status === 'rejected'} onClick={() => setStatus(item.id, 'rejected')} />
          </group>
        );
      })}
    </group>
  );
}

function ShareTab(p: XRHudInWorldProps) {
  const isLive = !!p.liveCode;
  return (
    <group>
      <Text position={[0, 0.105, 0]} fontSize={0.012} color={isLive ? '#22c55e' : '#94a3b8'}
            anchorX="center" anchorY="middle">
        {isLive ? '● TRANSMITINDO AO VIVO' : '○ Transmissão desligada'}
      </Text>
      {isLive ? (
        <>
          <Text position={[0, 0.07, 0]} fontSize={0.010} color="#94a3b8" anchorX="center" anchorY="middle">
            Código da sala
          </Text>
          <Text position={[0, 0.04, 0]} fontSize={0.024} color="#3b82f6" anchorX="center" anchorY="middle">
            {p.liveCode}
          </Text>
          <Text position={[0, -0.005, 0]} fontSize={0.010} color="#cbd5e1" anchorX="center" anchorY="middle">
            {p.liveViewers ?? 0} espectador(es) conectado(s)
          </Text>
          <Text position={[0, -0.04, 0]} fontSize={0.008} color="#64748b" anchorX="center" anchorY="middle"
                maxWidth={0.45}>
            Os espectadores veem o ponto de vista 3D do operador, sem a câmera real (privacidade).
          </Text>
          <XR3DButton position={[0, -0.09, 0]} size={[0.18, 0.028]}
            label="✕ Encerrar transmissão" color="#dc2626"
            onClick={() => p.onStopLive?.()} />
        </>
      ) : (
        <>
          <Text position={[0, 0.04, 0]} fontSize={0.010} color="#cbd5e1" anchorX="center" anchorY="middle"
                maxWidth={0.45}>
            Inicie uma transmissão WebRTC para que cliente/supervisor acompanhem ao vivo (até 5 viewers, link público).
          </Text>
          <XR3DButton position={[0, -0.04, 0]} size={[0.22, 0.03]}
            label="📡 Iniciar transmissão" color="#3b82f6"
            onClick={() => p.onStartLive?.()} />
          <Text position={[0, -0.09, 0]} fontSize={0.008} color="#64748b" anchorX="center" anchorY="middle"
                maxWidth={0.45}>
            {getBroadcastSource() ? '✓ Mirror opaco ativo' : 'Mirror será criado ao iniciar'}
          </Text>
        </>
      )}
    </group>
  );
}

function WebXRTab() {
  const xrFeatures = useModelStore((s) => s.xrFeatures);
  const setXRFeature = useModelStore((s) => s.setXRFeature);
  const reset = useModelStore((s) => s.resetXRFeatures);
  const keys: { k: keyof typeof xrFeatures; label: string }[] = [
    { k: 'handTracking',    label: 'Hand' },
    { k: 'planeDetection',  label: 'Planes' },
    { k: 'hitTest',         label: 'HitTest' },
    { k: 'domOverlay',      label: 'DOM Ovl' },
    { k: 'anchors',         label: 'Anchors' },
    { k: 'meshDetection',   label: 'Mesh' },
    { k: 'depthSensing',    label: 'Depth' },
    { k: 'layers',          label: 'Layers' },
    { k: 'bodyTracking',    label: 'Body' },
  ];
  return (
    <group>
      <Text position={[-0.24, 0.115, 0]} fontSize={0.0085} color="#94a3b8" anchorX="left" maxWidth={0.48}>
        Desligue uma feature por vez para descobrir qual ativa o grid de segurança do Quest.
      </Text>
      <Text position={[-0.24, 0.095, 0]} fontSize={0.0075} color="#f59e0b" anchorX="left" maxWidth={0.48}>
        Mudanças entram em vigor ao sair e re-entrar no AR.
      </Text>
      {keys.map((it, i) => {
        const col = i % 3;
        const row = Math.floor(i / 3);
        const x = -0.18 + col * 0.14;
        const y = 0.05 - row * 0.045;
        const on = xrFeatures[it.k];
        return (
          <XR3DButton key={it.k}
            position={[x, y, 0]} size={[0.125, 0.034]}
            label={`${it.label}  ${on ? 'ON' : 'OFF'}`}
            active={on} onClick={() => setXRFeature(it.k, !on)}
            fontSize={0.0085} />
        );
      })}
      <XR3DButton position={[0, -0.14, 0]} size={[0.18, 0.028]}
        label="↺ Resetar (todas ON)" onClick={reset} fontSize={0.009} />
    </group>
  );
}

function CaptureTab() {
  const rec = useCanvasRecorder();
  const addScreenshot = useModelStore((s) => s.addScreenshot);

  const onPhoto = () => {
    const dataUrl = captureScreenshot();
    if (dataUrl) addScreenshot(dataUrl);
  };

  const statusColor =
    rec.status === 'recording' ? '#dc2626' :
    rec.status === 'paused' ? '#f59e0b' : '#94a3b8';
  const statusLabel =
    rec.status === 'recording' ? `● REC ${formatElapsed(rec.elapsedMs)}` :
    rec.status === 'paused' ? `❚❚ PAUSADO ${formatElapsed(rec.elapsedMs)}` :
    '○ Pronto para gravar';

  return (
    <group>
      <Text position={[-0.24, 0.115, 0]} fontSize={0.0085} color="#94a3b8" anchorX="left" maxWidth={0.48}>
        Capture fotos ou grave a sessão AR (vídeo .webm baixado ao parar).
      </Text>

      <Text position={[0, 0.075, 0]} fontSize={0.014} color={statusColor}
            anchorX="center" anchorY="middle">
        {statusLabel}
      </Text>

      {/* Foto */}
      <XR3DButton position={[-0.13, 0.02, 0]} size={[0.18, 0.038]}
        label="📸 Tirar Foto" color="#3b82f6"
        onClick={onPhoto} fontSize={0.011} />

      {/* Iniciar / Parar gravação */}
      {rec.status === 'idle' ? (
        <XR3DButton position={[0.09, 0.02, 0]} size={[0.18, 0.038]}
          label="● Iniciar Gravação" color="#dc2626"
          onClick={startRecording} fontSize={0.011} />
      ) : (
        <XR3DButton position={[0.09, 0.02, 0]} size={[0.18, 0.038]}
          label="■ Parar e Salvar" color="#dc2626" active
          onClick={stopRecording} fontSize={0.011} />
      )}

      {/* Pause / Resume */}
      {rec.status === 'recording' && (
        <XR3DButton position={[0, -0.045, 0]} size={[0.2, 0.034]}
          label="❚❚ Pausar" color="#f59e0b"
          onClick={pauseRecording} fontSize={0.011} />
      )}
      {rec.status === 'paused' && (
        <XR3DButton position={[0, -0.045, 0]} size={[0.2, 0.034]}
          label="▶ Retomar" color="#22c55e" active
          onClick={resumeRecording} fontSize={0.011} />
      )}

      <Text position={[-0.24, -0.105, 0]} fontSize={0.0075} color="#64748b"
            anchorX="left" maxWidth={0.48}>
        Foto → .png  |  Vídeo → .webm  |  Arquivos vão para a pasta Downloads do navegador.
      </Text>
    </group>
  );
}

function RecIndicator() {
  const rec = useCanvasRecorder();
  if (rec.status === 'idle') return null;
  const color = rec.status === 'recording' ? '#dc2626' : '#f59e0b';
  const label = rec.status === 'recording'
    ? `● REC ${formatElapsed(rec.elapsedMs)}`
    : `❚❚ ${formatElapsed(rec.elapsedMs)}`;
  return (
    <group position={[0.09, 0.018, 0]}>
      <mesh>
        <planeGeometry args={[0.078, 0.022]} />
        <meshBasicMaterial color="#0a0a0a" transparent opacity={0.9} />
      </mesh>
      <Text position={[0, 0, 0.001]} fontSize={0.0085} color={color}
            anchorX="center" anchorY="middle">
        {label}
      </Text>
    </group>
  );
}

function CalibrationTab() {
  const activeModelId = useModelStore((s) => s.activeModelId);
  const models = useModelStore((s) => s.models);
  const setCalibrationStore = useModelStore((s) => s.setCalibration);
  const active = models.find((m) => m.id === activeModelId);

  // Escuta o barramento de calibração do XR
  const [, force] = useState(0);
  useEffect(() => subscribeXRCalibration(() => force((t) => t + 1)), []);

  const isCalibrating = xrCalibration.step !== 'idle' && xrCalibration.step !== 'done';
  const isDone = xrCalibration.step === 'done';
  
  const isCubeMode = xrCalibration.alignType === 'cube';
  const isVirtRealMode = xrCalibration.alignType === 'virt-real';

  const onClickCube = () => {
    if (isCalibrating && isCubeMode) {
      cancelXRCalibration();
      return;
    }
    if (isDone && isCubeMode) {
      cancelXRCalibration();
      return;
    }
    if (!active) {
      toast.error('Selecione uma peça antes de calibrar');
      return;
    }
    if (active.locked) {
      toast.error('Peça travada — destranque a peça para calibrar');
      return;
    }
    startXRCalibration(active.id, 'cube');
  };

  const onClickVirtReal = () => {
    if (isCalibrating && isVirtRealMode) {
      cancelXRCalibration();
      return;
    }
    if (isDone && isVirtRealMode) {
      cancelXRCalibration();
      return;
    }
    if (!active) {
      toast.error('Selecione uma peça antes de calibrar');
      return;
    }
    if (active.locked) {
      toast.error('Peça travada — destranque a peça para calibrar');
      return;
    }
    startXRCalibration(active.id, 'virt-real');
  };

  const onResetCalibration = () => {
    if (!active) return;
    setCalibrationStore(active.id, null);
    toast.success('Calibração removida');
  };

  const STEP_HINTS_AR: Record<string, string> = {
    'await-cube-1': '1/3 - Clique numa face do Cubo à direita',
    'await-model-1': '1/3 - Aponte e clique na face correspondente da peça',
    'await-cube-2': '2/3 - Clique em outra face do Cubo',
    'await-model-2': '2/3 - Clique na face correspondente da peça',
    'await-cube-3': '3/3 (Verificar) - Clique em uma 3ª face do Cubo (opcional)',
    'await-model-3': '3/3 - Clique na face correspondente da peça',
    'await-real-1': '1/3 Real - Clique na 1ª superfície da peça REAL',
    'await-virtual-1': '1/3 Virtual - Clique na 1ª correspondente da peça VIRTUAL',
    'await-real-2': '2/3 Real - Clique na 2ª superfície da peça REAL',
    'await-virtual-2': '2/3 Virtual - Clique na 2ª correspondente da peça VIRTUAL',
    'await-real-3': '3/3 Real - Clique na 3ª superfície da peça REAL',
    'await-virtual-3': '3/3 Virtual - Clique na 3ª correspondente da peça VIRTUAL',
    'done': 'Calibração concluída com sucesso!',
  };

  const currentHint = STEP_HINTS_AR[xrCalibration.step] ?? 'Selecione "Cubo" ou "Virt/Real" para calibrar o modelo';

  // Configurações dinâmicas de estados de botão
  let cubeLabel = 'Cubo';
  let cubeActive = false;
  let cubeColor = '#3b82f6';
  
  let vrLabel = 'Virt/Real';
  let vrActive = false;
  let vrColor = '#3b82f6';

  if (isCalibrating) {
    if (isCubeMode) {
      cubeLabel = 'Cancelar';
      cubeActive = true;
      cubeColor = '#d97706';
    } else {
      cubeColor = '#475569'; 
    }

    if (isVirtRealMode) {
      vrLabel = 'Cancelar';
      vrActive = true;
      vrColor = '#d97706';
    } else {
      vrColor = '#475569';
    }
  } else if (isDone) {
    if (isCubeMode) {
      cubeLabel = 'Concluído';
      cubeActive = true;
      cubeColor = '#22c55e';
    }
    if (isVirtRealMode) {
      vrLabel = 'Concluído';
      vrActive = true;
      vrColor = '#22c55e';
    }
  }

  return (
    <group>
      {/* Coluna da esquerda: Informações e Fluxo */}
      <Text position={[-0.24, 0.11, 0]} fontSize={0.012} color="#3b82f6" anchorX="left" anchorY="middle">
        Calibração 3D da Peça
      </Text>
      
      <Text position={[-0.24, 0.07, 0]} fontSize={0.008} color="#cbd5e1" anchorX="left" anchorY="top" maxWidth={0.28}>
        Alinhe o modelo virtual 3D com a peça real usando o Cubo ou clique em 3 pontos de controle ("Virt/Real").
      </Text>

      {/* Caixa de status do passo atual */}
      <group position={[-0.24, 0.00, 0]}>
        <mesh position={[0.13, 0, -0.0005]}>
          <planeGeometry args={[0.26, 0.05]} />
          <meshBasicMaterial color="#111827" transparent opacity={0.65} />
        </mesh>
        <Text position={[0.01, 0, 0.001]} fontSize={0.008} color={isDone ? '#22c55e' : isCalibrating ? '#f59e0b' : '#ffffff'} anchorX="left" anchorY="middle" maxWidth={0.24}>
          {currentHint}
        </Text>
        {isDone && Number.isFinite(xrCalibration.verifyErrorDeg) && isCubeMode && (
          <Text position={[0.01, -0.016, 0.001]} fontSize={0.007} color="#22c55e" anchorX="left" anchorY="middle">
            Erro residual calculado: {xrCalibration.verifyErrorDeg.toFixed(1)}°
          </Text>
        )}
      </group>

      {/* Botões na parte inferior esquerda */}
      <group position={[-0.24, -0.06, 0]}>
        <XR3DButton
          position={[0.045, 0, 0]}
          size={[0.08, 0.026]}
          label={cubeLabel}
          active={cubeActive}
          color={cubeColor}
          onClick={onClickCube}
          fontSize={0.008}
        />

        <XR3DButton
          position={[0.135, 0, 0]}
          size={[0.08, 0.026]}
          label={vrLabel}
          active={vrActive}
          color={vrColor}
          onClick={onClickVirtReal}
          fontSize={0.008}
        />
        
        {active?.calibrationQuat && !isCalibrating && (
          <XR3DButton
            position={[0.225, 0, 0]}
            size={[0.08, 0.026]}
            label="Limpar"
            color="#dc2626"
            onClick={onResetCalibration}
            fontSize={0.008}
          />
        )}
      </group>

      <Text position={[-0.24, -0.11, 0]} fontSize={0.007} color="#64748b" anchorX="left" maxWidth={0.28}>
        {active ? `Peça ativa: ${active.fileName}` : 'Selecione uma peça na aba "Cena"'}
      </Text>

      {/* Coluna da direita: Cubo de views 3D interativo */}
      <group position={[0.14, -0.01, 0.04]}>
        <XRViewCube activeModelId={activeModelId} size={0.075} />
        {/* Tripé dos eixos abaixo do cubo */}
        <group position={[0, -0.06, -0.04]} scale={[0.035, 0.035, 0.035]}>
          <arrowHelper args={[new THREE.Vector3(1, 0, 0), new THREE.Vector3(0, 0, 0), 0.7, 0xff4444, 0.18, 0.12]} />
          <arrowHelper args={[new THREE.Vector3(0, 1, 0), new THREE.Vector3(0, 0, 0), 0.7, 0x44ff66, 0.18, 0.12]} />
          <arrowHelper args={[new THREE.Vector3(0, 0, 1), new THREE.Vector3(0, 0, 0), 0.7, 0x4488ff, 0.18, 0.12]} />
        </group>
        <Text position={[0, 0.065, -0.04]} fontSize={0.008} color="#cbd5e1" anchorX="center" anchorY="middle">
          Cubo de Calibração
        </Text>
      </group>
    </group>
  );
}
