import React, { useEffect, useRef, useState, useMemo, Suspense } from 'react';
import { useParams, useNavigate } from 'react-router-dom';

interface ErrorBoundaryProps {
  children: React.ReactNode;
  fallback: React.ReactNode;
}

interface ErrorBoundaryState {
  hasError: boolean;
}

class ModelErrorBoundary extends React.Component<ErrorBoundaryProps, ErrorBoundaryState> {
  constructor(props: ErrorBoundaryProps) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError() {
    return { hasError: true };
  }

  componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
    console.error("🚨 [ModelErrorBoundary] Falha de renderização/rede no modelo:", error, errorInfo);
  }

  render() {
    if (this.state.hasError) {
      return this.props.fallback;
    }
    return this.props.children;
  }
}
import { Canvas, useFrame } from '@react-three/fiber';
import { OrbitControls, Text, useGLTF, Billboard, Html } from '@react-three/drei';
import * as THREE from 'three';
import { supabase } from '@/integrations/supabase/client';
import { useModelStore, type SceneModel } from '@/stores/useModelStore';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Checkbox } from '@/components/ui/checkbox';
import { toast } from 'sonner';
import {
  Users, MessageSquare, Mic, MicOff, Home, Send,
  ArrowRight, ChevronLeft, ChevronRight, Share2, LogOut,
  RotateCw, Award, ShieldAlert, Maximize2, Minimize2, Box,
  Settings, Check
} from 'lucide-react';

// Interfaces tipadas para evitar any
interface AvatarPreset {
  id: number;
  name: string;
  desc: string;
  color: string;
  url: string;
}

interface PresentationState {
  rotation: number[];
  scale: number;
  sectionEnabled: boolean;
  sectionAxis: 'x' | 'y' | 'z';
  sectionLevel: number;
  sectionInvert: boolean;
  modelUrl?: string;
  modelFileName?: string;
  modelFileSize?: number;
}

interface PeerData {
  username: string;
  avatarId: number;
  chairId: string;
  role: string;
  cargo: string;
  empresa: string;
  presence_ref: string;
  allowedAvatars?: number[];
}

// Detector nativo de suporte ao WebGL
function isWebGLAvailable() {
  try {
    const canvas = document.createElement('canvas');
    return !!(
      window.WebGLRenderingContext && 
      (canvas.getContext('webgl') || canvas.getContext('experimental-webgl'))
    );
  } catch (e) {
    return false;
  }
}

// Hook de verificação de suporte a WebGL no cliente
function useWebGLSupport() {
  const [supported, setSupported] = useState(true);
  useEffect(() => {
    setSupported(isWebGLAvailable());
  }, []);
  return supported;
}

// --- Configurações da Mesa de Reunião ---
const CHAIRS = [
  { id: '1', name: 'Assento 1', pos: [-1.2, 0.95, -1.45], rot: [0, 0, 0], lookAt: [0, 0.95, 0] },
  { id: '2', name: 'Assento 2', pos: [-0.4, 0.95, -1.45], rot: [0, 0, 0], lookAt: [0, 0.95, 0] },
  { id: '3', name: 'Assento 3', pos: [0.4, 0.95, -1.45], rot: [0, 0, 0], lookAt: [0, 0.95, 0] },
  { id: '4', name: 'Assento 4', pos: [1.2, 0.95, -1.45], rot: [0, 0, 0], lookAt: [0, 0.95, 0] },
  { id: '5', name: 'Assento 5', pos: [1.2, 0.95, 1.45], rot: [0, Math.PI, 0], lookAt: [0, 0.95, 0] },
  { id: '6', name: 'Assento 6', pos: [0.4, 0.95, 1.45], rot: [0, Math.PI, 0], lookAt: [0, 0.95, 0] },
  { id: '7', name: 'Assento 7', pos: [-0.4, 0.95, 1.45], rot: [0, Math.PI, 0], lookAt: [0, 0.95, 0] },
  { id: '8', name: 'Assento 8', pos: [-1.2, 0.95, 1.45], rot: [0, Math.PI, 0], lookAt: [0, 0.95, 0] },
];

const AVATAR_PRESETS: AvatarPreset[] = [
  // Masculinos (1 a 10)
  { id: 1, name: 'Leo', desc: 'Negro, cabelo curto preto', url: '/avatars/avatar_1.png', color: '#ef4444' },
  { id: 2, name: 'Marcus', desc: 'Loiro, cabelo curto', url: '/avatars/avatar_2.png', color: '#b45309' },
  { id: 3, name: 'Arthur', desc: 'Ruivo com barba', url: '/avatars/avatar_3.png', color: '#eab308' },
  { id: 4, name: 'Jin', desc: 'Asiático, cabelo preto liso', url: '/avatars/avatar_4.png', color: '#3b82f6' },
  { id: 5, name: 'Mateo', desc: 'Castanho, cabelo cacheado', url: '/avatars/avatar_5.png', color: '#f97316' },
  { id: 6, name: 'Malik', desc: 'Negro, careca com barba', url: '/avatars/avatar_6.png', color: '#84cc16' },
  { id: 7, name: 'Oliver', desc: 'Cabelo grisalho com óculos', url: '/avatars/avatar_7.png', color: '#06b6d4' },
  { id: 8, name: 'Carlos', desc: 'Latino com bigode', url: '/avatars/avatar_8.png', color: '#6366f1' },
  { id: 9, name: 'Yuki', desc: 'Cabelo espetado azul escuro', url: '/avatars/avatar_9.png', color: '#a855f7' },
  { id: 10, name: 'Elijah', desc: 'Negro com dreadlocks', url: '/avatars/avatar_10.png', color: '#ec4899' },
  // Femininos (11 a 20)
  { id: 11, name: 'Sophia', desc: 'Morena, cabelo longo castanho', url: '/avatars/avatar_11.png', color: '#10b981' },
  { id: 12, name: 'Aisha', desc: 'Negra com turbante/lenço', url: '/avatars/avatar_12.png', color: '#78350f' },
  { id: 13, name: 'Isabella', desc: 'Loira, cabelo longo ondulado', url: '/avatars/avatar_13.png', color: '#1e293b' },
  { id: 14, name: 'Chloe', desc: 'Ruiva, corte canal/bob', url: '/avatars/avatar_14.png', color: '#ca8a04' },
  { id: 15, name: 'Mei', desc: 'Asiática, cabelo com franja', url: '/avatars/avatar_15.png', color: '#f43f5e' },
  { id: 16, name: 'Elena', desc: 'Castanha, cabelo afro volumoso', url: '/avatars/avatar_16.png', color: '#14b8a6' },
  { id: 17, name: 'Zara', desc: 'Cabelo roxo moderno', url: '/avatars/avatar_17.png', color: '#0ea5e9' },
  { id: 18, name: 'Naomi', desc: 'Negra de óculos e rabo de cavalo', url: '/avatars/avatar_18.png', color: '#4f46e5' },
  { id: 19, name: 'Harper', desc: 'Corte pixie rosa', url: '/avatars/avatar_19.png', color: '#d946ef' },
  { id: 20, name: 'Amara', desc: 'Negra com tranças', url: '/avatars/avatar_20.png', color: '#f59e0b' }
];

const SKIN_COLORS = ['#fed7aa', '#fdba74', '#f59e0b', '#d97706', '#9a3412', '#ffedd5'];

// Classes Tailwind estáticas para evitar inline styles no list view dos avatares
const getAvatarBgClass = (avatarId: number): string => {
  const classes = [
    'bg-red-500/20 text-red-400',
    'bg-amber-800/20 text-amber-500',
    'bg-yellow-500/20 text-yellow-400',
    'bg-blue-500/20 text-blue-400',
    'bg-orange-500/20 text-orange-400',
    'bg-lime-500/20 text-lime-400',
    'bg-cyan-500/20 text-cyan-400',
    'bg-indigo-500/20 text-indigo-400',
    'bg-purple-500/20 text-purple-400',
    'bg-pink-500/20 text-pink-400',
    'bg-emerald-500/20 text-emerald-400',
    'bg-amber-950/40 text-amber-600',
    'bg-slate-700/20 text-slate-300',
    'bg-yellow-600/20 text-yellow-500',
    'bg-rose-500/20 text-rose-400',
    'bg-teal-500/20 text-teal-400',
    'bg-sky-500/20 text-sky-400',
    'bg-indigo-600/20 text-indigo-500',
    'bg-fuchsia-500/20 text-fuchsia-400',
    'bg-amber-500/20 text-amber-400'
  ];
  return classes[(avatarId - 1) % classes.length] || classes[0];
};

// --- Subcomponentes 3D ---

// ==========================================
// BACKUP DOS AVATARES PROCEDURAIS ORIGINAIS
// ==========================================
function MiiAvatarBackup({ 
  avatarId, 
  username, 
  isTalking, 
  scale = 1, 
  isLastChatSender = false,
  ...props 
}: { 
  avatarId: number; 
  username: string; 
  isTalking?: boolean; 
  scale?: number;
  isLastChatSender?: boolean;
} & Record<string, unknown>) {
  const groupRef = useRef<THREE.Group>(null);
  const ringRef = useRef<THREE.Mesh>(null);
  const headRef = useRef<THREE.Group>(null);
  const lastSenderRef = useRef(isLastChatSender);
  const pulseEndTimeRef = useRef(0);

  useEffect(() => {
    if (isLastChatSender && !lastSenderRef.current) {
      pulseEndTimeRef.current = Date.now() + 1500;
    }
    lastSenderRef.current = isLastChatSender;
  }, [isLastChatSender]);
  
  const avatarUrl = useMemo(() => {
    const preset = AVATAR_PRESETS.find((p) => p.id === avatarId);
    return preset ? preset.url : `/avatars/avatar_${avatarId}.png`;
  }, [avatarId]);

  useFrame((state) => {
    if (groupRef.current && props.position && Array.isArray(props.position) && props.position.length >= 2) {
      groupRef.current.position.y = (props.position[1] as number) + Math.sin(state.clock.getElapsedTime() * 2 + avatarId) * 0.012;
    }

    if (headRef.current) {
      if (isTalking) {
        headRef.current.position.y = 0.16 + Math.abs(Math.sin(state.clock.getElapsedTime() * 12)) * 0.025;
        headRef.current.rotation.z = Math.sin(state.clock.getElapsedTime() * 12) * 0.06;
      } else {
        headRef.current.position.y = THREE.MathUtils.lerp(headRef.current.position.y, 0.16, 0.15);
        headRef.current.rotation.z = THREE.MathUtils.lerp(headRef.current.rotation.z, 0, 0.15);
      }
    }

    if (ringRef.current) {
      const now = Date.now();
      const material = ringRef.current.material as THREE.MeshBasicMaterial;

      if (isTalking) {
        material.color.set('#3b82f6');
        material.opacity = 0.6 + Math.sin(state.clock.getElapsedTime() * 10) * 0.3;
        ringRef.current.scale.set(1, 1, 1);
      } else if (isLastChatSender) {
        material.color.set('#eab308');
        const isPulsing = now < pulseEndTimeRef.current;
        if (isPulsing) {
          material.opacity = 0.5 + Math.sin(state.clock.getElapsedTime() * 25) * 0.4;
          const s = 1.0 + Math.sin(state.clock.getElapsedTime() * 25) * 0.15;
          ringRef.current.scale.set(s, s, 1);
        } else {
          material.opacity = 0.75;
          ringRef.current.scale.set(1, 1, 1);
        }
      }
    }
  });

  const positionVector = useMemo(() => {
    if (props.position && Array.isArray(props.position)) {
      return new THREE.Vector3(props.position[0] as number, props.position[1] as number, props.position[2] as number);
    }
    return new THREE.Vector3(0, 0, 0);
  }, [props.position]);

  const rotationEuler = useMemo(() => {
    if (props.rotation && Array.isArray(props.rotation)) {
      return new THREE.Euler(props.rotation[0] as number, props.rotation[1] as number, props.rotation[2] as number);
    }
    return new THREE.Euler(0, 0, 0);
  }, [props.rotation]);

  return (
    <group ref={groupRef} position={positionVector} rotation={rotationEuler} scale={scale}>
      <group position={[0, 0.38, 0]}>
        <mesh position={[0, 0, -0.001]}>
          <planeGeometry args={[0.44, 0.1]} />
          <meshBasicMaterial color="#0f172a" transparent opacity={0.7} />
        </mesh>
        <Text fontSize={0.048} color="#ffffff" anchorX="center" anchorY="middle" fontWeight="bold">
          {username}
        </Text>
      </group>

      {(isTalking || isLastChatSender) && (
        <mesh ref={ringRef} rotation={[-Math.PI / 2, 0, 0]} position={[0, -0.01, 0]}>
          <ringGeometry args={[0.065, 0.075, 32]} />
          <meshBasicMaterial color="#3b82f6" transparent opacity={0.7} side={THREE.DoubleSide} />
        </mesh>
      )}

      {/* Cabeça do Avatar: Toon Head do Dicebear em HTML Transformado em 3D Plano (olhando para a mesa) */}
      <group ref={headRef} position={[0, 0.16, 0]}>
        <Html transform center distanceFactor={1.2}>
          <div className="w-16 h-16 flex items-center justify-center pointer-events-none select-none">
            <img 
              src={avatarUrl} 
              alt={username}
              className="w-full h-full object-contain drop-shadow-md"
              onError={(e) => {
                (e.currentTarget as HTMLImageElement).src = `https://ui-avatars.com/api/?name=${encodeURIComponent(username || 'U')}&background=475569&color=fff&size=128&rounded=true`;
              }}
            />
          </div>
        </Html>
      </group>

      {/* Base cônica para dar uma sustentação 3D estilizada */}
      <mesh position={[0, 0.03, 0]}>
        <coneGeometry args={[0.045, 0.1, 32]} />
        <meshStandardMaterial color="#475569" roughness={0.5} metalness={0.2} transparent opacity={0.8} />
      </mesh>
    </group>
  );
}

// ==========================================
// CLASSES E COMPONENTES DE RESILIÊNCIA
// ==========================================
class AvatarErrorBoundary extends React.Component<{ fallback: React.ReactNode; children: React.ReactNode }, { hasError: boolean }> {
  constructor(props: { fallback: React.ReactNode; children: React.ReactNode }) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError() {
    return { hasError: true };
  }

  componentDidCatch(error: Error) {
    console.warn("🚨 [AvatarErrorBoundary] Falha ao carregar o modelo GLB do avatar. Utilizando o avatar de fallback procedural.", error);
  }

  render() {
    if (this.state.hasError) {
      return this.props.fallback;
    }
    return this.props.children;
  }
}

// O componente principal MiiAvatar agora é um wrapper resiliente com Suspense e ErrorBoundary
function MiiAvatar(props: { 
  avatarId: number; 
  username: string; 
  isTalking?: boolean; 
  scale?: number;
  isLastChatSender?: boolean;
} & Record<string, unknown>) {
  const preset = AVATAR_PRESETS.find((p) => p.id === props.avatarId);
  const isPng = preset?.url.endsWith('.png');

  if (isPng) {
    return <MiiAvatarBackup {...props} />;
  }

  return (
    <AvatarErrorBoundary fallback={<MiiAvatarBackup {...props} />}>
      <Suspense fallback={<MiiAvatarBackup {...props} />}>
        <RealMiiAvatar {...props} />
      </Suspense>
    </AvatarErrorBoundary>
  );
}

// ==========================================
// NOVOS AVATARES REALISTAS (READY PLAYER ME)
// ==========================================
function RealMiiAvatar({ 
  avatarId, 
  username, 
  isTalking, 
  scale = 1, 
  isLastChatSender = false,
  ...props 
}: { 
  avatarId: number; 
  username: string; 
  isTalking?: boolean; 
  scale?: number;
  isLastChatSender?: boolean;
} & Record<string, unknown>) {
  const groupRef = useRef<THREE.Group>(null);
  const ringRef = useRef<THREE.Mesh>(null);
  const lastSenderRef = useRef(isLastChatSender);
  const pulseEndTimeRef = useRef(0);

  // Monitora quando este avatar se torna o último a escrever no chat
  useEffect(() => {
    if (isLastChatSender && !lastSenderRef.current) {
      pulseEndTimeRef.current = Date.now() + 1500;
    }
    lastSenderRef.current = isLastChatSender;
  }, [isLastChatSender]);

  // Obtém o preset correto para pegar a URL do avatar GLB
  const preset = useMemo(() => {
    return AVATAR_PRESETS.find((p) => p.id === avatarId) || AVATAR_PRESETS[0];
  }, [avatarId]);

  // Carrega o modelo 3D GLB de forma assíncrona
  const { scene } = useGLTF(preset.url);
  const clone = useMemo(() => scene.clone(), [scene]);

  // Configuração inicial do clone para sombra e materiais
  useEffect(() => {
    if (clone) {
      clone.traverse((child) => {
        if (child instanceof THREE.Mesh) {
          child.castShadow = true;
          child.receiveShadow = true;
          if (child.material) {
            child.material.roughness = 0.8;
          }
        }
      });
    }
  }, [clone]);

  useFrame((state) => {
    // Flutuação sutil de respiração/repouso
    if (groupRef.current && props.position && Array.isArray(props.position) && props.position.length >= 2) {
      groupRef.current.position.y = (props.position[1] as number) + Math.sin(state.clock.getElapsedTime() * 1.5 + avatarId) * 0.008 - 0.22;
    }

    // Animação de sincronização labial (lip-sync) nativa baseada em Morph Targets
    if (clone) {
      clone.traverse((child) => {
        if (child instanceof THREE.SkinnedMesh && child.morphTargetInfluences) {
          const dict = child.morphTargetDictionary;
          if (dict) {
            const jawOpenIdx = dict['jawOpen'] ?? dict['viseme_sil'] ?? dict['mouthOpen'];
            const mouthSmileIdx = dict['mouthSmile'] ?? dict['mouthSmileLeft'];
            
            if (jawOpenIdx !== undefined) {
              if (isTalking) {
                // Abre e fecha a boca no ritmo do clock
                child.morphTargetInfluences[jawOpenIdx] = 0.15 + Math.abs(Math.sin(state.clock.getElapsedTime() * 18)) * 0.6;
              } else {
                child.morphTargetInfluences[jawOpenIdx] = 0;
              }
            }

            if (mouthSmileIdx !== undefined) {
              child.morphTargetInfluences[mouthSmileIdx] = 0.25;
            }
          }
        }
      });
    }

    // Animação do anel de fala / chat
    if (ringRef.current) {
      const now = Date.now();
      const material = ringRef.current.material as THREE.MeshBasicMaterial;

      if (isTalking) {
        material.color.set('#3b82f6');
        material.opacity = 0.6 + Math.sin(state.clock.getElapsedTime() * 10) * 0.3;
        ringRef.current.scale.set(1, 1, 1);
      } else if (isLastChatSender) {
        material.color.set('#eab308');
        
        const isPulsing = now < pulseEndTimeRef.current;
        if (isPulsing) {
          material.opacity = 0.5 + Math.sin(state.clock.getElapsedTime() * 25) * 0.4;
          const s = 1.0 + Math.sin(state.clock.getElapsedTime() * 25) * 0.15;
          ringRef.current.scale.set(s, s, 1);
        } else {
          material.opacity = 0.75;
          ringRef.current.scale.set(1, 1, 1);
        }
      }
    }
  });

  const positionVector = useMemo(() => {
    if (props.position && Array.isArray(props.position)) {
      return new THREE.Vector3(props.position[0] as number, (props.position[1] as number) - 0.22, props.position[2] as number);
    }
    return new THREE.Vector3(0, -0.22, 0);
  }, [props.position]);

  const rotationEuler = useMemo(() => {
    if (props.rotation && Array.isArray(props.rotation)) {
      return new THREE.Euler(props.rotation[0] as number, props.rotation[1] as number, props.rotation[2] as number);
    }
    return new THREE.Euler(0, 0, 0);
  }, [props.rotation]);

  return (
    <group ref={groupRef} position={positionVector} rotation={rotationEuler} scale={scale}>
      {/* Balão de Nome acima da cabeça */}
      <group position={[0, 0.9, 0]}>
        <mesh position={[0, 0, -0.001]}>
          <planeGeometry args={[0.52, 0.11]} />
          <meshBasicMaterial color="#0f172a" transparent opacity={0.8} />
        </mesh>
        <Text fontSize={0.052} color="#ffffff" anchorX="center" anchorY="middle" fontWeight="bold">
          {username}
        </Text>
      </group>

      {/* Modelo GLB Realista Clonado */}
      <primitive object={clone} scale={0.42} position={[0, 0.02, 0]} />

      {/* Indicador de Fala & Chat */}
      {(isTalking || isLastChatSender) && (
        <mesh 
          ref={ringRef}
          rotation={[-Math.PI / 2, 0, 0]} 
          position={[0, 0.35, 0.02]}
        >
          <ringGeometry args={[0.075, 0.088, 32]} />
          <meshBasicMaterial color="#3b82f6" transparent opacity={0.7} side={THREE.DoubleSide} />
        </mesh>
      )}
    </group>
  );
}

// Carregador e Escalador Inteligente da Maquete Holográfica
// Carregador e Escalador Inteligente da Maquete Holográfica
function HologramModel({ model, presentationState }: { model: SceneModel; presentationState: PresentationState }) {
  const { scene } = useGLTF(model.url);
  const clone = useMemo(() => scene.clone(), [scene]);
  const presentationGroupRef = useRef<THREE.Group>(null);
  const baseScaleRef = useRef<number>(1);
  const centerRef = useRef<THREE.Vector3>(new THREE.Vector3());

  // Calcula escala de aproximadamente 1 metro para caber na mesa (apenas UMA vez no carregamento)
  useEffect(() => {
    if (!clone) return;

    // Reseta rotação e escala para obter o bounding box original limpo
    const oldRot = clone.rotation.clone();
    const oldScale = clone.scale.clone();
    clone.rotation.set(0, 0, 0);
    clone.scale.setScalar(1);

    const box = new THREE.Box3().setFromObject(clone);
    const size = new THREE.Vector3();
    box.getSize(size);
    const maxDim = Math.max(size.x, size.y, size.z);
    
    if (maxDim > 0) {
      const targetSize = 0.95;
      const scaleFactor = targetSize / maxDim;
      baseScaleRef.current = scaleFactor;
      
      const center = new THREE.Vector3();
      box.getCenter(center);
      centerRef.current.copy(center);
    }

    // Restaura
    clone.rotation.copy(oldRot);
    clone.scale.copy(oldScale);
  }, [clone]);

  // Aplica cor do modelo nos materiais do clone
  useEffect(() => {
    if (!clone || !model.color) return;
    clone.traverse((child) => {
      if (child instanceof THREE.Mesh) {
        // Clone do material para evitar afetar cache global do R3F
        if (Array.isArray(child.material)) {
          child.material = child.material.map(m => m.clone());
        } else {
          child.material = child.material.clone();
        }

        const materials = Array.isArray(child.material) ? child.material : [child.material];
        materials.forEach((mat: THREE.Material) => {
          if (mat instanceof THREE.MeshStandardMaterial) {
            mat.color.set(model.color);
            mat.needsUpdate = true;
          }
        });
      }
    });
  }, [clone, model.color]);

  // Aplica transformações de Rotação e Escala compartilhadas no grupo externo de apresentação
  useFrame(() => {
    if (presentationGroupRef.current && presentationState) {
      const { rotation, scale } = presentationState;
      if (rotation) {
        presentationGroupRef.current.rotation.x = rotation[0];
        presentationGroupRef.current.rotation.y = rotation[1];
        presentationGroupRef.current.rotation.z = rotation[2];
      }
      if (scale) {
        presentationGroupRef.current.scale.setScalar(baseScaleRef.current * scale);
      }
    }
  });

  // Aplica Planos de Corte (clippingPlanes) nos materiais
  useEffect(() => {
    if (!clone || !presentationState) return;
    const { sectionEnabled, sectionAxis, sectionLevel, sectionInvert } = presentationState;

    if (!sectionEnabled) {
      clone.traverse((obj) => {
        if (obj instanceof THREE.Mesh) {
          const mats = Array.isArray(obj.material) ? obj.material : [obj.material];
          mats.forEach((mat) => {
            if (mat) {
              mat.clippingPlanes = [];
              mat.needsUpdate = true;
            }
          });
        }
      });
      return;
    }

    const normal = new THREE.Vector3();
    if (sectionAxis === 'x') normal.set(sectionInvert ? -1 : 1, 0, 0);
    else if (sectionAxis === 'y') normal.set(0, sectionInvert ? -1 : 1, 0);
    else if (sectionAxis === 'z') normal.set(0, 0, sectionInvert ? -1 : 1);

    // Ajusta a distância baseado no bounding box original e no nível do corte
    const box = new THREE.Box3().setFromObject(clone);
    const size = new THREE.Vector3();
    box.getSize(size);
    const minVal = sectionAxis === 'x' ? box.min.x : sectionAxis === 'y' ? box.min.y : box.min.z;
    const maxVal = sectionAxis === 'x' ? box.max.x : sectionAxis === 'y' ? box.max.y : box.max.z;
    const distance = minVal + (maxVal - minVal) * sectionLevel;

    const plane = new THREE.Plane(normal, -distance);

    clone.traverse((obj) => {
      if (obj instanceof THREE.Mesh) {
        const mats = Array.isArray(obj.material) ? obj.material : [obj.material];
        mats.forEach((mat) => {
          if (mat) {
            mat.clippingPlanes = [plane];
            mat.clipShadows = true;
            mat.needsUpdate = true;
          }
        });
      }
    });
  }, [clone, presentationState]);

  // Translações, Rotações finas e Escala fina nativas da maquete vindas do Viewer
  const fineTuning = model.fineTuning || { posX: 0, posY: 0, posZ: 0, rotX: 0, rotY: 0, rotZ: 0, scale: 1 };
  const rotXRad = (fineTuning.rotX * Math.PI) / 180;
  const rotYRad = (fineTuning.rotY * Math.PI) / 180;
  const rotZRad = (fineTuning.rotZ * Math.PI) / 180;
  const s = fineTuning.scale ?? 1;

  // Quaternion de calibração nativo da maquete
  const calQuatArr = model.calibrationQuat;
  const calQuat = useMemo(() => {
    if (!calQuatArr) return new THREE.Quaternion();
    return new THREE.Quaternion(calQuatArr[0], calQuatArr[1], calQuatArr[2], calQuatArr[3]);
  }, [calQuatArr]);

  return (
    // Grupo Externo de Apresentação Compartilhada
    <group ref={presentationGroupRef}>
      {/* Grupo de Translação Fina */}
      <group position={[fineTuning.posX, fineTuning.posY, fineTuning.posZ]}>
        {/* Grupo de Rotação Fina e Escala Fina */}
        <group rotation={[rotXRad, rotYRad, rotZRad]} scale={[s, s, s]}>
          {/* Grupo de Calibração */}
          <group quaternion={calQuat}>
            {/* Grupo de Centralização do Bounding Box (para girar em torno do seu centro geométrico) */}
            <group position={[-centerRef.current.x, -centerRef.current.y, -centerRef.current.z]}>
              <primitive object={clone} />
            </group>
          </group>
        </group>
      </group>
    </group>
  );
}

// Cenário da Sala de Reunião Clara
function ThreeMeetingRoomScene({ currentActiveModel, presentationState, isFocusMode }: { currentActiveModel: SceneModel | null; presentationState: PresentationState; isFocusMode: boolean }) {
  const tableGeom = useMemo(() => {
    // Geometria da mesa em U / Retangular de cantos arredondados
    const shape = new THREE.Shape();
    shape.moveTo(-1.6, -1.1);
    shape.lineTo(1.6, -1.1);
    shape.quadraticCurveTo(1.9, -1.1, 1.9, -0.8);
    shape.lineTo(1.9, 0.8);
    shape.quadraticCurveTo(1.9, 1.1, 1.6, 1.1);
    shape.lineTo(-1.6, 1.1);
    shape.quadraticCurveTo(-1.9, 1.1, -1.9, 0.8);
    shape.lineTo(-1.9, -0.8);
    shape.quadraticCurveTo(-1.9, -1.1, -1.6, -1.1);

    const hole = new THREE.Path();
    hole.absellipse(0, 0, 0.9, 0.45, 0, Math.PI * 2, true);
    shape.holes.push(hole);

    return new THREE.ExtrudeGeometry(shape, { depth: 0.06, bevelEnabled: true, bevelThickness: 0.01, bevelSize: 0.01, bevelSegments: 3 });
  }, []);

  return (
    <group>
      {/* Luzes da Sala / Foco */}
      <ambientLight intensity={isFocusMode ? 0.7 : 0.8} />
      <directionalLight position={isFocusMode ? [5, 5, 5] : [4, 6, 4]} intensity={1.5} castShadow={!isFocusMode} />
      
      {isFocusMode && (
        <color attach="background" args={['#090d16']} />
      )}

      {!isFocusMode && (
        <>
          {/* Piso Clara */}
          <mesh rotation={[-Math.PI / 2, 0, 0]} position={[0, 0, 0]}>
            <planeGeometry args={[12, 8]} />
            <meshStandardMaterial color="#e2e8f0" roughness={0.4} metalness={0.1} />
          </mesh>
          
          {/* Tapete Central */}
          <mesh rotation={[-Math.PI / 2, 0, 0]} position={[0, 0.001, 0]}>
            <planeGeometry args={[4.8, 3.2]} />
            <meshStandardMaterial color="#94a3b8" roughness={0.7} />
          </mesh>

          {/* Paredes Claras */}
          <mesh position={[0, 2, -4]}>
            <planeGeometry args={[12, 4]} />
            <meshStandardMaterial color="#f1f5f9" roughness={0.9} />
          </mesh>
          {/* Janelas Panorâmicas */}
          <mesh position={[-6, 2, 0]} rotation={[0, Math.PI / 2, 0]}>
            <planeGeometry args={[8, 4]} />
            <meshStandardMaterial color="#bae6fd" roughness={0.1} emissive="#bae6fd" emissiveIntensity={0.4} />
          </mesh>
          <mesh position={[6, 2, 0]} rotation={[0, -Math.PI / 2, 0]}>
            <planeGeometry args={[8, 4]} />
            <meshStandardMaterial color="#bae6fd" roughness={0.1} emissive="#bae6fd" emissiveIntensity={0.4} />
          </mesh>

          {/* Mesa Elíptica/Retangular com furo central (Madeira Mel Carvalho Clara) */}
          <group position={[0, 0.8, 0]} rotation={[Math.PI / 2, 0, 0]}>
            <mesh geometry={tableGeom} castShadow receiveShadow>
              <meshStandardMaterial color="#d97706" roughness={0.2} metalness={0.1} />
            </mesh>
          </group>

          {/* Pés da mesa (Cromados) */}
          {[-1.3, 1.3].map((x) =>
            [-0.7, 0.7].map((z) => (
              <mesh key={`${x}-${z}`} position={[x, 0.4, z]} castShadow receiveShadow>
                <cylinderGeometry args={[0.035, 0.035, 0.8]} />
                <meshStandardMaterial color="#d4d4d8" metalness={0.9} roughness={0.1} />
              </mesh>
            ))
          )}

          {/* Projetor de Holograma / Círculo centralizado desenhado na mesa */}
          <mesh position={[0, 0.861, 0]} rotation={[-Math.PI / 2, 0, 0]}>
            <ringGeometry args={[0.22, 0.25, 32]} />
            <meshBasicMaterial color="#0ea5e9" transparent opacity={0.6} />
          </mesh>
        </>
      )}

      {/* Modelo 3D da Maquete Holográfica */}
      <group position={isFocusMode ? [0, 0, 0] : [0, 1.23, 0]}>
        <ModelErrorBoundary fallback={
          // Se falhar ao carregar o modelo (ex: blob local do host inacessível por convidados), renderiza o holograma geométrico
          <group rotation={[0, Date.now() * 0.00012, 0]}>
            <mesh position={[0, 0, 0]}>
              <octahedronGeometry args={[0.22]} />
              <meshStandardMaterial color="#f43f5e" transparent opacity={0.7} wireframe emissive="#f43f5e" emissiveIntensity={0.5} />
            </mesh>
            <mesh position={[0, -0.15, 0]}>
              <boxGeometry args={[0.3, 0.02, 0.3]} />
              <meshStandardMaterial color="#ef4444" transparent opacity={0.4} />
            </mesh>
          </group>
        }>
          <Suspense fallback={
            <mesh>
              <sphereGeometry args={[0.1, 16, 16]} />
              <meshBasicMaterial color="#00f5ff" wireframe />
            </mesh>
          }>
            {currentActiveModel ? (
              <HologramModel model={currentActiveModel} presentationState={presentationState} />
            ) : (
              // Holograma Padrão Geométrico se não houver maquete carregada
              <group rotation={[0, Date.now() * 0.00012, 0]}>
                <mesh position={[0, 0, 0]}>
                  <octahedronGeometry args={[0.22]} />
                  <meshStandardMaterial color="#0ea5e9" transparent opacity={0.7} wireframe emissive="#0ea5e9" emissiveIntensity={0.5} />
                </mesh>
                <mesh position={[0, 0, 0]} rotation={[0, Math.PI / 4, 0]}>
                  <boxGeometry args={[0.25, 0.04, 0.25]} />
                  <meshStandardMaterial color="#3b82f6" transparent opacity={0.4} emissive="#3b82f6" emissiveIntensity={0.2} />
                </mesh>
              </group>
            )}
          </Suspense>
        </ModelErrorBoundary>
      </group>

      {/* Renderizar as Cadeiras Físicas da mesa - Ocultadas no Modo Foco */}
      {!isFocusMode && CHAIRS.map((chair) => (
        <group key={chair.id} position={[chair.pos[0], 0, chair.pos[2]]} rotation={[0, Math.atan2(chair.lookAt[0] - chair.pos[0], chair.lookAt[2] - chair.pos[2]), 0]}>
          {/* Base giratória metálica */}
          <mesh position={[0, 0.25, 0]}>
            <cylinderGeometry args={[0.015, 0.015, 0.5]} />
            <meshStandardMaterial color="#a1a1aa" metalness={0.9} roughness={0.1} />
          </mesh>
          {/* Pés base */}
          <mesh position={[0, 0.02, 0]} rotation={[-Math.PI / 2, 0, 0]}>
            <ringGeometry args={[0, 0.22, 4]} />
            <meshStandardMaterial color="#71717a" metalness={0.85} roughness={0.2} />
          </mesh>
          {/* Assento */}
          <mesh position={[0, 0.52, 0]}>
            <boxGeometry args={[0.28, 0.05, 0.26]} />
            <meshStandardMaterial color="#334155" roughness={0.7} />
          </mesh>
          {/* Encosto */}
          <mesh position={[0, 0.78, -0.11]} rotation={[0.08, 0, 0]}>
            <boxGeometry args={[0.26, 0.44, 0.04]} />
            <meshStandardMaterial color="#334155" roughness={0.7} />
          </mesh>
        </group>
      ))}

      {/* Iluminação Clara da Sala - Ocultada no Modo Foco */}
      {!isFocusMode && (
        <>
          <hemisphereLight color="#ffffff" groundColor="#64748b" intensity={1.4} />
          <directionalLight position={[6, 12, 6]} intensity={1.8} castShadow />
          <directionalLight position={[-6, 8, -6]} intensity={0.5} />
          <pointLight position={[0, 3.5, 0]} intensity={2.0} color="#0ea5e9" distance={8} />
        </>
      )}
    </group>
  );
}

// --- Componente Principal da Tela ---

export default function MeetingRoom() {
  const isWebGLSupported = useWebGLSupport();
  const { roomId } = useParams<{ roomId?: string }>();
  const navigate = useNavigate();
  const models = useModelStore((s) => s.models);
  const activeModelId = useModelStore((s) => s.activeModelId);
  const activeModel = useMemo(() => {
    return models.find((m) => m.id === activeModelId) || null;
  }, [models, activeModelId]);

  // Estados do Lobby
  const [inRoom, setInRoom] = useState(false);
  const [isConnecting, setIsConnecting] = useState(false);
  const [isFocusMode, setIsFocusMode] = useState(false);
  const [name, setName] = useState(() => localStorage.getItem('tsxr_meeting_user_name') || '');
  const [cargo, setCargo] = useState(() => localStorage.getItem('tsxr_meeting_user_cargo') || '');
  const [empresa, setEmpresa] = useState(() => localStorage.getItem('tsxr_meeting_user_empresa') || '');
  const [isPresenter, setIsPresenter] = useState(() => {
    const saved = localStorage.getItem('tsxr_meeting_user_is_presenter');
    if (saved !== null) return saved === 'true';
    return !roomId;
  });
  const [selectedAvatar, setSelectedAvatar] = useState(() => Number(localStorage.getItem('tsxr_meeting_user_avatar')) || 1);
  const [selectedChair, setSelectedChair] = useState(() => localStorage.getItem('tsxr_meeting_user_chair') || '1');
  const [inputRoomId, setInputRoomId] = useState(roomId || '');

  // Estados da Sala (Conexão Supabase)
  const [peers, setPeers] = useState<Record<string, PeerData>>({});

  // Lista de avatares permitidos (IDs de 1 a 20). Por padrão, todos estão ativos.
  const [allowedAvatars, setAllowedAvatars] = useState<number[]>(() => {
    return Array.from({ length: 20 }, (_, i) => i + 1);
  });
  const [isAvatarConfigOpen, setIsAvatarConfigOpen] = useState(false);

  const updateAllowedAvatars = async (newAllowed: number[]) => {
    setAllowedAvatars(newAllowed);
    if (isPresenter && channelRef.current) {
      console.log("⚙️ [MeetingRoom] Atualizando metadados de Presence com avatares permitidos:", newAllowed);
      await channelRef.current.track({
        username: name.substring(0, 10),
        avatarId: selectedAvatar,
        chairId: selectedChair,
        role: isPresenter ? 'presenter' : 'guest',
        cargo: cargo.trim() || 'Colaborador',
        empresa: empresa.trim() || 'SteelXR Corp',
        joinedAt: new Date().toISOString(),
        allowedAvatars: newAllowed
      });
    }
  };
  
  const mergedPeers = useMemo(() => {
    if (!inRoom) return peers;
    
    // Se o usuário local já estiver no peers (via sync do Supabase), usamos o peers original
    if (peers[selectedChair]) {
      return peers;
    }
    
    // Caso contrário, injetamos o usuário local no dicionário temporário
    return {
      ...peers,
      [selectedChair]: {
        presence_ref: 'local_user',
        username: name,
        avatarId: selectedAvatar,
        chairId: selectedChair,
        role: isPresenter ? 'presenter' : 'guest',
        cargo: cargo || 'Apresentador',
        empresa: empresa || 'SteelXR Corp',
        joinedAt: new Date().toISOString()
      } as unknown as PeerData
    };
  }, [peers, inRoom, selectedChair, name, selectedAvatar, isPresenter, cargo, empresa]);

  const activeUsersCount = useMemo(() => Object.keys(mergedPeers).length, [mergedPeers]);

  const [chatMessages, setChatMessages] = useState<{ id: string; sender: string; text: string; time: string }[]>([]);
  const [newMessage, setNewMessage] = useState('');
  const [lastChatSender, setLastChatSender] = useState<string | null>(null);
  const [isMuted, setIsMuted] = useState(false);
  const [isTalking, setIsTalking] = useState(false);
  const [roomCode, setRoomCode] = useState(roomId || '');
  const [activeTab, setActiveTab] = useState<'chat' | 'participants'>('participants');

  // Estado compartilhado da Apresentação da maquete
  const [presentationState, setPresentationState] = useState<PresentationState>({
    rotation: [0, 0, 0],
    scale: 1,
    sectionEnabled: false,
    sectionAxis: 'y',
    sectionLevel: 0.0,
    sectionInvert: false
  });

  // Carrega modificações da peça vindas do Viewer se houver
  useEffect(() => {
    const savedState = localStorage.getItem('tsxr_initial_meeting_state');
    if (savedState) {
      try {
        const parsed = JSON.parse(savedState) as PresentationState;
        setPresentationState(parsed);
        console.log('🔄 [MeetingRoom] Estado inicial carregado do Viewer:', parsed);
      } catch (err) {
        console.error('Falha ao carregar estado inicial do Viewer', err);
      }
      localStorage.removeItem('tsxr_initial_meeting_state');
    }
  }, []);

  const channelRef = useRef<ReturnType<typeof supabase.channel> | null>(null);
  const chatScrollRef = useRef<HTMLDivElement>(null);

  // Se o roomId mudar na url, atualiza o checkbox isPresenter e o inputRoomId
  useEffect(() => {
    setIsPresenter(!roomId);
    setInputRoomId(roomId || '');
  }, [roomId]);

  // Simulação de detecção de áudio
  useEffect(() => {
    if (!inRoom || isMuted) {
      setIsTalking(false);
      return;
    }
    const interval = setInterval(() => {
      setIsTalking(Math.random() > 0.7);
    }, 1500);
    return () => clearInterval(interval);
  }, [inRoom, isMuted]);

  useEffect(() => {
    if (chatScrollRef.current) {
      chatScrollRef.current.scrollTop = chatScrollRef.current.scrollHeight;
    }
  }, [chatMessages]);

  // --- ESCUTA DO LOBBY EM TEMPO REAL ---
  // Conecta ao canal antes do lobby finalizar para ler assentos e avatares ocupados na sala digitada
  useEffect(() => {
    if (!inputRoomId || inputRoomId.trim().length < 3 || inRoom || isConnecting) {
      setPeers({});
      return;
    }

    const roomIdUpper = inputRoomId.trim().toUpperCase();
    console.log(`🔌 [Lobby Watcher] Escutando sala: ${roomIdUpper}`);

    const tempChannel = supabase.channel(`meeting_room_${roomIdUpper}`, {
      config: {
        presence: { key: 'lobby_watcher_' + Math.random().toString(36).substring(3, 8) }
      }
    });

    tempChannel
      .on('presence', { event: 'sync' }, () => {
        const state = tempChannel.presenceState();
        console.log("👥 [Lobby Watcher Sync] Estado de presença bruto:", state);
        const formattedPeers: Record<string, PeerData> = {};
        let remoteAllowed: number[] | null = null;
        
        Object.keys(state).forEach((key) => {
          if (key.startsWith('lobby_watcher_')) return;
          const presences = state[key] as unknown as PeerData[];
          if (presences && presences.length > 0) {
            presences.forEach((presence) => {
              if (presence && presence.chairId && presence.username) {
                formattedPeers[presence.chairId] = {
                  ...presence,
                  avatarId: Number(presence.avatarId) || 1,
                  cargo: presence.cargo || 'Colaborador',
                  empresa: presence.empresa || 'SteelXR Corp',
                  role: presence.role || 'guest'
                };

                if (presence.role === 'presenter' && Array.isArray(presence.allowedAvatars)) {
                  remoteAllowed = presence.allowedAvatars;
                }
              }
            });
          }
        });
        
        console.log("👥 [Lobby Watcher Sync] Peers formatados:", formattedPeers);
        setPeers(formattedPeers);

        if (remoteAllowed) {
          console.log("⚙️ [Lobby Watcher Sync] Sincronizados avatares permitidos remotos:", remoteAllowed);
          setAllowedAvatars(remoteAllowed);
        }
      })
      .subscribe();

    return () => {
      console.log(`🔌 [Lobby Watcher] Desinscrevendo escuta passiva da sala: ${roomIdUpper}`);
      tempChannel.unsubscribe();
      supabase.removeChannel(tempChannel);
    };
  }, [inputRoomId, inRoom, isConnecting]);

  // Envia as atualizações de apresentação via Broadcast para a sala inteira
  const handlePresentationChange = (updatedFields: Partial<PresentationState>) => {
    if (!isPresenter || !channelRef.current) return;
    
    const store = useModelStore.getState();
    const currentModel = store.models.find(m => m.id === store.activeModelId) || null;

    const newState = {
      ...presentationState,
      ...updatedFields,
      modelUrl: currentModel?.url,
      modelFileName: currentModel?.fileName,
      modelFileSize: currentModel?.fileSize
    } as PresentationState;
    
    setPresentationState(newState);

    channelRef.current.send({
      type: 'broadcast',
      event: 'presentation_update',
      payload: newState
    });
  };

  // Inicializa o Supabase Presence & Broadcast para conexões oficiais
  const connectToRoom = async (targetRoomId: string) => {
    if (!name.trim()) {
      toast.error('Digite seu nome primeiro');
      return;
    }

    // Salva no localStorage para auto-preenchimento conveniente
    localStorage.setItem('tsxr_meeting_user_name', name);
    localStorage.setItem('tsxr_meeting_user_cargo', cargo);
    localStorage.setItem('tsxr_meeting_user_empresa', empresa);
    localStorage.setItem('tsxr_meeting_user_avatar', String(selectedAvatar));
    localStorage.setItem('tsxr_meeting_user_chair', selectedChair);
    localStorage.setItem('tsxr_meeting_user_is_presenter', String(isPresenter));
    
    // Validar se o avatar já está em uso por outra pessoa
    const avatarInUse = Object.values(peers).find((p) => p.avatarId === selectedAvatar);
    if (avatarInUse) {
      toast.error(`O avatar "${AVATAR_PRESETS[selectedAvatar - 1].name}" já está em uso por ${avatarInUse.username}. Escolha outro!`);
      return;
    }

    // Validar se a cadeira está ocupada
    if (Object.keys(peers).includes(selectedChair)) {
      toast.error('O assento selecionado já está ocupado por outro participante. Por favor, selecione outro assento.');
      return;
    }

    // Ativa o estado de conexão e aguarda 120ms para a escuta do lobby se desmontar totalmente
    setIsConnecting(true);
    await new Promise((resolve) => setTimeout(resolve, 120));

    const finalRoomId = targetRoomId.trim().toUpperCase() || Math.random().toString(36).substring(3, 8).toUpperCase();
    setRoomCode(finalRoomId);

    // Evita o erro "cannot add presence callbacks ... after subscribe()" removendo canais antigos com o mesmo tópico
    const oldChannels = supabase.getChannels().filter(c => c.topic === `realtime:meeting_room_${finalRoomId}`);
    for (const old of oldChannels) {
      console.log(`🔌 [MeetingRoom] Removendo canal antigo ativo para evitar conflitos: ${old.topic}`);
      await supabase.removeChannel(old);
    }
    
    console.log(`🔌 [MeetingRoom] Conectando à sala: ${finalRoomId} como ${isPresenter ? 'Apresentador' : 'Convidado'}`);

    const channel = supabase.channel(`meeting_room_${finalRoomId}`, {
      config: {
        broadcast: { self: true }
      },
    });

    channelRef.current = channel;

    // Sincroniza participantes online com tolerância a múltiplos formatos e falhas de conexão
    channel
      .on('presence', { event: 'sync' }, () => {
        const state = channel.presenceState();
        console.log("👥 [Presence Sync] Estado de presença bruto da reunião:", state);
        const formattedPeers: Record<string, PeerData> = {};
        let remoteAllowed: number[] | null = null;
        
        Object.keys(state).forEach((key) => {
          if (key.startsWith('lobby_watcher_')) return;
          const presences = state[key] as unknown as PeerData[];
          if (presences && presences.length > 0) {
            presences.forEach((presence) => {
              if (presence && presence.chairId && presence.username) {
                formattedPeers[presence.chairId] = {
                  ...presence,
                  avatarId: Number(presence.avatarId) || 1,
                  cargo: presence.cargo || 'Colaborador',
                  empresa: presence.empresa || 'SteelXR Corp',
                  role: presence.role || 'guest'
                };

                if (presence.role === 'presenter' && Array.isArray(presence.allowedAvatars)) {
                  remoteAllowed = presence.allowedAvatars;
                }
              }
            });
          }
        });
        console.log("👥 [Presence Sync] Peers formatados:", formattedPeers);
        setPeers(formattedPeers);

        if (!isPresenter && remoteAllowed) {
          console.log("⚙️ [Presence Sync] Sincronizando avatares permitidos remotos na sala conectada:", remoteAllowed);
          setAllowedAvatars(remoteAllowed);
        }
      })
      .on('presence', { event: 'join' }, ({ key, newPresences }) => {
        if (key.startsWith('lobby_watcher_')) return;
        toast.info(`"${(newPresences[0] as unknown as PeerData)?.username}" sentou-se no assento ${key}`);
      })
      .on('presence', { event: 'leave' }, ({ key, leftPresences }) => {
        if (key.startsWith('lobby_watcher_')) return;
        toast.info(`"${(leftPresences[0] as unknown as PeerData)?.username}" liberou o assento ${key}`);
      });

    // Escuta mensagens do Chat via Broadcast
    channel.on('broadcast', { event: 'chat_msg' }, (payload) => {
      setChatMessages((prev) => [
        ...prev,
        {
          id: Math.random().toString(),
          sender: payload.payload.sender,
          text: payload.payload.text,
          time: new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }),
        },
      ]);
      setLastChatSender(payload.payload.sender);
    });

    // Escuta atualizações de Apresentação da Maquete via Broadcast (apenas para convidados)
    channel.on('broadcast', { event: 'presentation_update' }, (payload) => {
      if (!isPresenter) {
        const data = payload.payload as PresentationState;
        setPresentationState(data);

        // Se o apresentador propagar um modelo remoto que o convidado não tem ativo, carrega
        if (data.modelUrl && data.modelFileName) {
          const store = useModelStore.getState();
          const hasModel = store.models.some(m => m.fileName === data.modelFileName);
          if (!hasModel) {
            console.log(`📥 [MeetingRoom] Carregando modelo remoto do apresentador: ${data.modelFileName}`);
            useModelStore.getState().addModel({
              fileName: data.modelFileName,
              fileSize: data.modelFileSize || 0,
              url: data.modelUrl
            });
          } else {
            const existing = store.models.find(m => m.fileName === data.modelFileName);
            if (existing && store.activeModelId !== existing.id) {
              useModelStore.getState().setActiveModel(existing.id);
            }
          }
        }
      }
    });

    // Inscrever no WebSocket
    channel.subscribe(async (status) => {
      if (status === 'SUBSCRIBED') {
        // Envia as informações completas para o Presence do Supabase
        await channel.track({
          username: name.substring(0, 10),
          avatarId: selectedAvatar,
          chairId: selectedChair,
          role: isPresenter ? 'presenter' : 'guest',
          cargo: cargo.trim() || 'Colaborador',
          empresa: empresa.trim() || 'SteelXR Corp',
          joinedAt: new Date().toISOString(),
          allowedAvatars: allowedAvatars
        });

        // Se for o apresentador, propaga o estado inicial de apresentação (vinda do Viewer) para todos
        if (isPresenter) {
          const store = useModelStore.getState();
          const currentModel = store.models.find(m => m.id === store.activeModelId) || null;
          channel.send({
            type: 'broadcast',
            event: 'presentation_update',
            payload: {
              ...presentationState,
              modelUrl: currentModel?.url,
              modelFileName: currentModel?.fileName,
              modelFileSize: currentModel?.fileSize
            }
          });
        }

        setInRoom(true);
        setIsConnecting(false);
        toast.success(`Entrou na sala de reunião: ${finalRoomId}`);
        navigate(`/meeting/${finalRoomId}`, { replace: true });
      } else if (status === 'CHANNEL_ERROR') {
        setIsConnecting(false);
        toast.error('Erro ao conectar ao canal de reuniões.');
      }
    });
  };

  // Enviar Mensagem de Chat
  const handleSendMessage = () => {
    if (!newMessage.trim() || !channelRef.current) return;
    const senderName = name.substring(0, 10);
    channelRef.current.send({
      type: 'broadcast',
      event: 'chat_msg',
      payload: {
        sender: senderName,
        text: newMessage.trim(),
      },
    });
    setChatMessages((prev) => [
      ...prev,
      {
        id: Math.random().toString(),
        sender: senderName,
        text: newMessage.trim(),
        time: new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }),
      },
    ]);
    setLastChatSender(senderName);
    setNewMessage('');
  };

  // Sair da Sala de Reunião
  const handleLeaveRoom = async () => {
    if (channelRef.current) {
      await supabase.removeChannel(channelRef.current);
    }
    setInRoom(false);
    setIsConnecting(false);
    setPeers({});
    setChatMessages([]);
    navigate('/');
  };

  const occupiedChairs = useMemo(() => {
    return Object.keys(peers).filter(k => !k.startsWith('lobby_watcher_'));
  }, [peers]);

  // Checar se o avatar selecionado no lobby está em uso
  const isAvatarInUse = useMemo(() => {
    return Object.values(peers).find((p) => p.avatarId === selectedAvatar);
  }, [peers, selectedAvatar]);

  // Lista de avatares disponíveis para este usuário escolher
  const availableAvatars = useMemo(() => {
    if (isPresenter) {
      return AVATAR_PRESETS.map((p) => p.id);
    }
    // Para convidados, filtra apenas os IDs permitidos pelo apresentador
    return AVATAR_PRESETS.map((p) => p.id).filter((id) => allowedAvatars.includes(id));
  }, [isPresenter, allowedAvatars]);

  // Se o selectedAvatar atual não estiver na lista de permitidos, selecionamos o primeiro disponível
  useEffect(() => {
    if (availableAvatars.length > 0 && !availableAvatars.includes(selectedAvatar)) {
      setSelectedAvatar(availableAvatars[0]);
    }
  }, [availableAvatars, selectedAvatar]);

  const nextAvatar = () => {
    if (availableAvatars.length === 0) return;
    const currentIndex = availableAvatars.indexOf(selectedAvatar);
    const nextIndex = (currentIndex + 1) % availableAvatars.length;
    setSelectedAvatar(availableAvatars[nextIndex]);
  };

  const prevAvatar = () => {
    if (availableAvatars.length === 0) return;
    const currentIndex = availableAvatars.indexOf(selectedAvatar);
    const prevIndex = (currentIndex - 1 + availableAvatars.length) % availableAvatars.length;
    setSelectedAvatar(availableAvatars[prevIndex]);
  };

  // --- Renderização do Lobby ---

  if (!inRoom) {
    const currentAvatar = AVATAR_PRESETS[selectedAvatar - 1];
    const canJoin = name.trim().length > 0 && !isAvatarInUse && !occupiedChairs.includes(selectedChair);

    return (
      <div className="flex min-h-screen flex-col items-center justify-center bg-background grid-industrial p-6">
        <div className="absolute top-6 left-6 flex items-center gap-2">
          <Button variant="ghost" size="icon" onClick={() => navigate('/')} className="text-muted-foreground hover:text-foreground">
            <Home className="h-5 w-5" />
          </Button>
          <span className="font-mono text-xs uppercase tracking-widest text-muted-foreground">TrackSteelXR</span>
        </div>

        <div className="w-full max-w-4xl rounded-2xl border border-border bg-card/65 p-6 md:p-10 shadow-2xl backdrop-blur-md animate-in fade-in zoom-in-95 duration-200">
          <div className="mb-6 text-center">
            <h2 className="text-2xl font-bold tracking-tight text-foreground md:text-3xl">
              Lobby de <span className="text-primary">Reunião Virtual</span>
            </h2>
            <p className="mt-1 text-xs font-mono uppercase tracking-wider text-muted-foreground">
              Configure suas credenciais e escolha seu avatar
            </p>
          </div>

          <div className="grid grid-cols-1 gap-6 md:grid-cols-12">
            {/* Seletor de Avatar (Lado Esquerdo - 5 colunas) */}
            <div className="flex flex-col items-center justify-center rounded-xl border bg-muted/30 p-5 md:col-span-5 relative">
              <span className="absolute top-3 left-4 font-mono text-[9px] uppercase tracking-widest text-muted-foreground">Visual Avatar</span>
              
              {/* Enquadramento centralizado perfeito (Camera apontando e fov adequado) */}
              <div className="h-40 w-full flex items-center justify-center relative bg-slate-900/60 rounded-lg overflow-hidden border border-border">
                {isWebGLSupported ? (
                  <Canvas camera={{ position: [0, 0.11, 0.28], fov: 42 }}>
                    <ambientLight intensity={0.8} />
                    <directionalLight position={[2, 3, 2]} intensity={1.5} />
                    <pointLight position={[0, 0.15, 0.2]} intensity={1} color={currentAvatar.color} />
                    <MiiAvatar avatarId={selectedAvatar} username={name || 'Você'} position={[0, -0.04, 0]} isTalking={true} scale={0.6} />
                  </Canvas>
                ) : (
                  <div className="flex flex-col items-center justify-center h-full w-full bg-slate-950/80 p-4 text-center">
                    <ShieldAlert className="h-7 w-7 text-amber-500 animate-pulse mb-1" />
                    <span className="font-mono text-[9px] font-bold text-amber-500 uppercase tracking-wider">WebGL Desativado</span>
                    <span className="text-[8px] text-slate-400 mt-1 max-w-[180px] leading-relaxed">
                      Aceleração por hardware inativa. O avatar 3D não pôde ser pré-visualizado.
                    </span>
                  </div>
                )}

                {/* Aviso se o avatar estiver em uso na sala */}
                {isAvatarInUse && (
                  <div className="absolute inset-0 bg-black/75 backdrop-blur-sm flex flex-col items-center justify-center text-center p-3 animate-in fade-in duration-200">
                    <ShieldAlert className="h-7 w-7 text-destructive animate-bounce mb-1" />
                    <span className="font-mono text-[10px] font-bold text-destructive uppercase tracking-wider">Avatar em Uso</span>
                    <span className="text-[9px] text-slate-300 mt-1 max-w-xs px-2 leading-snug">
                      Este visual já está ocupado por <strong className="text-primary uppercase block truncate">{isAvatarInUse.username}</strong>
                    </span>
                  </div>
                )}

                <Button variant="ghost" size="icon" className="absolute left-2 h-8 w-8 rounded-full border bg-background/50 hover:bg-background z-10" onClick={prevAvatar}>
                  <ChevronLeft className="h-4 w-4" />
                </Button>
                <Button variant="ghost" size="icon" className="absolute right-2 h-8 w-8 rounded-full border bg-background/50 hover:bg-background z-10" onClick={nextAvatar}>
                  <ChevronRight className="h-4 w-4" />
                </Button>
              </div>

              <div className="mt-3 text-center w-full px-2">
                <span className="font-mono text-xs font-bold uppercase tracking-wider text-primary">
                  {currentAvatar.name}
                </span>
                <p className="text-[9px] text-muted-foreground mt-0.5">{currentAvatar.desc}</p>
                
                {isPresenter && (
                  <Button 
                    type="button"
                    variant="outline" 
                    size="sm" 
                    onClick={() => setIsAvatarConfigOpen(true)}
                    className="mt-3 w-full font-mono text-[9px] uppercase tracking-wider gap-1 border-primary/40 hover:bg-primary/10 text-primary-foreground bg-primary/5 h-8"
                  >
                    <Settings className="h-3.5 w-3.5" />
                    Gerenciar Avatares ({allowedAvatars.length} ativos)
                  </Button>
                )}
              </div>

              {/* Formulário de Identificação: Nome, Cargo e Empresa agrupados sequencialmente na esquerda */}
              <div className="mt-4 w-full space-y-3">
                <div className="space-y-1">
                  <label className="font-mono text-[9px] uppercase tracking-wider text-muted-foreground block">Seu Nome (Máx 10 letras)</label>
                  <Input
                    type="text"
                    maxLength={10}
                    placeholder="Nome do usuário"
                    value={name}
                    onChange={(e) => setName(e.target.value)}
                    className="font-semibold text-center uppercase font-mono tracking-wider text-xs h-9"
                  />
                </div>
                
                <div className="space-y-1">
                  <label className="font-mono text-[9px] uppercase tracking-wider text-muted-foreground block">Cargo / Função</label>
                  <Input
                    type="text"
                    placeholder="Ex: Eng. Civil"
                    value={cargo}
                    onChange={(e) => setCargo(e.target.value)}
                    className="text-xs h-9 text-center"
                  />
                </div>
                
                <div className="space-y-1">
                  <label className="font-mono text-[9px] uppercase tracking-wider text-muted-foreground block">Empresa</label>
                  <Input
                    type="text"
                    placeholder="Ex: Steel Co."
                    value={empresa}
                    onChange={(e) => setEmpresa(e.target.value)}
                    className="text-xs h-9 text-center"
                  />
                </div>
              </div>
            </div>

            {/* Seleção do Assento, Host e Conexão (Lado Direito - 7 colunas) */}
            <div className="flex flex-col justify-between md:col-span-7 space-y-5">
              {/* Seleção do Assento (Exibe quem está ocupando em tempo real) */}
              <div className="space-y-2">
                <span className="font-mono text-[9px] uppercase tracking-wider text-muted-foreground">Selecione seu Assento na Mesa</span>
                <div className="grid grid-cols-2 sm:grid-cols-4 gap-2">
                  {CHAIRS.map((chair) => {
                    const occupier = Object.values(peers).find((p) => p.chairId === chair.id);
                    const isOccupied = !!occupier;
                    const isSelected = selectedChair === chair.id;
                    return (
                      <Button
                        key={chair.id}
                        variant={isSelected ? 'default' : 'outline'}
                        className={`h-12 flex-col p-1 gap-0.5 text-[9px] font-mono ${
                          isOccupied ? 'border-destructive/40 text-destructive bg-destructive/10 cursor-not-allowed hover:bg-destructive/10' : ''
                        }`}
                        disabled={isOccupied}
                        onClick={() => setSelectedChair(chair.id)}
                      >
                        <span className="font-semibold">{chair.name}</span>
                        <span className={`text-[8px] truncate max-w-full font-bold uppercase ${
                          isOccupied ? 'text-destructive' : isSelected ? 'text-primary-foreground' : 'text-muted-foreground'
                        }`}>
                          {isOccupied ? occupier.username : isSelected ? 'Escolhido' : 'Livre'}
                        </span>
                      </Button>
                    );
                  })}
                </div>
              </div>

              {/* Papel e Código de Conexão */}
              <div className="rounded-xl border bg-muted/20 p-4 space-y-4">
                <div className="flex items-center space-x-2">
                  <Checkbox
                    id="presenter-mode"
                    checked={isPresenter}
                    onCheckedChange={(checked) => setIsPresenter(!!checked)}
                  />
                  <label
                    htmlFor="presenter-mode"
                    className="text-xs font-mono font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70 text-foreground cursor-pointer"
                  >
                    Entrar como Apresentador (Host) da Sala
                  </label>
                </div>

                <div className="space-y-1.5">
                  <label className="font-mono text-[9px] uppercase tracking-wider text-muted-foreground">Código da Sala (Vazio para criar nova)</label>
                  <Input
                    type="text"
                    placeholder="Ex: TS-X9F"
                    value={inputRoomId}
                    onChange={(e) => setInputRoomId(e.target.value.toUpperCase())}
                    className="font-mono tracking-widest font-bold text-center text-xs h-9"
                  />
                </div>

                <div className="flex gap-2.5 pt-1">
                  <Button variant="outline" className="flex-1 font-mono text-xs h-10" onClick={() => navigate('/')}>
                    Cancelar
                  </Button>
                  <Button 
                    className="flex-1 glow-primary font-mono text-xs h-10 gap-2" 
                    disabled={!canJoin}
                    onClick={() => connectToRoom(inputRoomId)}
                  >
                    Acessar Reunião <ArrowRight className="h-4 w-4" />
                  </Button>
                </div>
                
                {isAvatarInUse && (
                  <p className="text-[10px] text-destructive font-mono text-center">
                    * Escolha outro avatar para liberar o acesso.
                  </p>
                )}
              </div>
            </div>
          </div>
        </div>

        {/* Modal de Configuração de Avatares Permitidos (Apenas para o Apresentador) */}
        {isAvatarConfigOpen && (
          <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/85 backdrop-blur-sm p-4 animate-in fade-in duration-200">
            <div className="w-full max-w-3xl rounded-xl border border-primary/30 bg-slate-900/90 p-6 md:p-8 shadow-2xl backdrop-blur-md flex flex-col max-h-[85vh] animate-in zoom-in-95 duration-200">
              <div className="flex justify-between items-start border-b border-slate-800 pb-4 mb-4">
                <div>
                  <h3 className="text-lg font-bold text-primary font-mono uppercase tracking-wider">Avatares da Reunião</h3>
                  <p className="text-[10px] text-muted-foreground font-mono mt-0.5 uppercase tracking-wide">
                    Selecione entre 4 e 10 avatares que estarão disponíveis para a reunião
                  </p>
                </div>
                <div className="flex items-center gap-2">
                  <span className="font-mono text-xs px-2 py-0.5 rounded-full bg-slate-800 border text-slate-300">
                    {allowedAvatars.length} Selecionados
                  </span>
                </div>
              </div>

              {/* Grid dos Avatares para Seleção */}
              <div className="flex-1 overflow-y-auto pr-1 py-1 grid grid-cols-2 sm:grid-cols-4 md:grid-cols-5 gap-3">
                {AVATAR_PRESETS.map((preset) => {
                  const isSelected = allowedAvatars.includes(preset.id);
                  const isMale = preset.id <= 10;
                  
                  return (
                    <div 
                      key={preset.id}
                      onClick={() => {
                        if (isSelected) {
                          // Se desmarcar, verifica se fica com menos de 4
                          if (allowedAvatars.length <= 4) {
                            toast.warning('A reunião deve conter pelo menos 4 avatares disponíveis.');
                            return;
                          }
                          updateAllowedAvatars(allowedAvatars.filter(id => id !== preset.id));
                        } else {
                          // Se marcar, verifica se excede 10
                          if (allowedAvatars.length >= 10) {
                            toast.warning('Você pode selecionar no máximo 10 avatares.');
                            return;
                          }
                          updateAllowedAvatars([...allowedAvatars, preset.id]);
                        }
                      }}
                      className={`relative flex flex-col items-center justify-center p-3 rounded-lg border-2 cursor-pointer transition-all duration-200 hover:scale-105 select-none ${
                        isSelected 
                          ? 'border-primary bg-primary/10 shadow-[0_0_10px_rgba(59,130,246,0.3)]' 
                          : 'border-slate-800 bg-slate-950/40 hover:border-slate-700 hover:bg-slate-950/70'
                      }`}
                    >
                      {/* Badge Sexo */}
                      <span className={`absolute top-1 right-1.5 font-mono text-[7px] px-1 rounded uppercase font-bold ${
                        isMale ? 'bg-blue-500/20 text-blue-400' : 'bg-pink-500/20 text-pink-400'
                      }`}>
                        {isMale ? 'M' : 'F'}
                      </span>

                      {/* Miniatura da Imagem Local */}
                      <div className="w-14 h-14 bg-slate-900/60 rounded-full border overflow-hidden flex items-center justify-center mb-2">
                        <img 
                          src={preset.url} 
                          alt={preset.name}
                          className="w-12 h-12 object-contain"
                        />
                      </div>

                      <span className="font-mono text-[10px] font-bold text-slate-200">{preset.name}</span>
                      <span className="text-[8px] text-slate-400 text-center mt-0.5 line-clamp-1 leading-snug">{preset.desc}</span>

                      {/* Check Icon */}
                      {isSelected && (
                        <div className="absolute -bottom-1.5 -right-1 bg-primary text-primary-foreground rounded-full p-0.5 shadow-md">
                          <Check className="h-3 w-3" />
                        </div>
                      )}
                    </div>
                  );
                })}
              </div>

              {/* Botão de Fechar / Salvar */}
              <div className="border-t border-slate-800 pt-4 mt-4 flex justify-end gap-3">
                <Button 
                  type="button"
                  variant="default"
                  onClick={() => {
                    if (allowedAvatars.length < 4 || allowedAvatars.length > 10) {
                      toast.error('Selecione entre 4 e 10 avatares antes de continuar.');
                      return;
                    }
                    setIsAvatarConfigOpen(false);
                    toast.success('Configuração de avatares atualizada com sucesso!');
                  }}
                  className="font-mono text-xs glow-primary px-6 animate-pulse"
                >
                  Salvar Escolhas
                </Button>
              </div>
            </div>
          </div>
        )}
      </div>
    );
  }

  // --- Renderização da Sala de Reunião Ativa ---

  return (
    <div className="flex h-screen overflow-hidden bg-slate-950 text-white relative animate-in fade-in duration-350">
      {/* 3D Canvas - Sala Clara */}
      <div className="flex-1 h-full relative">
        {isWebGLSupported ? (
          <Canvas camera={{ position: [0, 2.5, 2.8], fov: 45 }} shadows gl={{ localClippingEnabled: true }}>
            <ThreeMeetingRoomScene currentActiveModel={activeModel} presentationState={presentationState} isFocusMode={isFocusMode} />
            
            {/* Renderizar avatares de TODOS na sala - Ocultados se modo foco */}
            {!isFocusMode && Object.keys(mergedPeers).map((chairKey) => {
              const peer = mergedPeers[chairKey];
              const chairConf = CHAIRS.find((c) => c.id === peer.chairId);
              if (!chairConf) return null;
              
              const isLocalUser = peer.chairId === selectedChair;

              return (
                <MiiAvatar
                  key={peer.presence_ref || 'local'}
                  avatarId={peer.avatarId}
                  username={isLocalUser ? `${peer.username} (Você)` : peer.username}
                  position={chairConf.pos}
                  rotation={chairConf.rot}
                  isTalking={isLocalUser ? isTalking : (isTalking && Math.random() > 0.5)}
                  isLastChatSender={peer.username === lastChatSender}
                  scale={4.8}
                />
              );
            })}

            <OrbitControls
              makeDefault
              enableDamping
              dampingFactor={0.05}
              minDistance={0.5}
              maxDistance={8}
              maxPolarAngle={Math.PI / 2 - 0.05}
              target={isFocusMode ? [0, 0, 0] : [0, 0.95, 0]}
            />
          </Canvas>
        ) : (
          <div className="flex-1 h-full flex flex-col items-center justify-center p-8 bg-slate-900 border border-slate-800 rounded-xl m-4 relative overflow-hidden">
            <div className="absolute inset-0 bg-gradient-to-br from-slate-950 via-slate-900 to-slate-950 opacity-95 z-0" />
            <div className="relative z-10 max-w-md text-center space-y-4">
              <div className="mx-auto w-16 h-16 rounded-full bg-amber-500/10 border border-amber-500/30 flex items-center justify-center animate-pulse">
                <ShieldAlert className="h-8 w-8 text-amber-500" />
              </div>
              <div className="space-y-2">
                <h3 className="text-xl font-bold tracking-tight text-slate-100 font-mono uppercase">WebGL Requerido</h3>
                <p className="text-xs text-slate-400 leading-relaxed">
                  Aceleração por hardware (WebGL) está desativada ou não é suportada por seu navegador/dispositivo atual.
                </p>
              </div>
              <div className="bg-slate-950/80 rounded-lg p-4 text-left border border-slate-800 text-[11px] font-mono text-slate-400 space-y-2">
                <span className="text-amber-500 font-bold uppercase block text-[10px] tracking-wider mb-1">Como resolver no Chrome:</span>
                <p>1. Vá em <code className="text-primary">chrome://settings/system</code></p>
                <p>2. Ative <code className="text-primary">"Usar aceleração de hardware quando disponível"</code></p>
                <p>3. Reinicie o navegador e recarregue esta página.</p>
              </div>
              <div className="text-[10px] text-muted-foreground italic">
                * Nota: O chat lateral, lista de participantes e chamadas continuam funcionando normalmente.
              </div>
            </div>
          </div>
        )}

        {/* Painel do Apresentador (Controles de Manipulação Sincronizados) */}
        {isPresenter && (
          <div className="absolute left-4 bottom-16 w-80 rounded-xl border border-primary/30 bg-slate-900/95 p-4 shadow-2xl backdrop-blur z-20 space-y-4 pointer-events-auto">
            <div className="flex items-center justify-between border-b border-slate-800 pb-2">
              <span className="font-mono text-xs font-bold text-primary flex items-center gap-1.5">
                <Award className="h-4 w-4 animate-pulse" /> Painel do Apresentador
              </span>
              <span className="font-mono text-[8px] bg-emerald-500/25 text-emerald-400 px-1.5 py-0.5 rounded uppercase font-semibold">Sincronizado</span>
            </div>

            {/* Rotação Y */}
            <div className="space-y-1">
              <div className="flex justify-between text-[10px] font-mono text-muted-foreground">
                <span>Giro da Peça (Horizontal)</span>
                <span>{Math.round((presentationState.rotation[1] * 180) / Math.PI)}°</span>
              </div>
              <input
                type="range"
                min={-Math.PI}
                max={Math.PI}
                step={0.05}
                title="Giro Horizontal"
                value={presentationState.rotation[1]}
                onChange={(e) => handlePresentationChange({ rotation: [0, parseFloat(e.target.value), 0] })}
                className="w-full h-1 bg-slate-800 rounded-lg appearance-none cursor-pointer accent-primary"
              />
            </div>

            {/* Escala */}
            <div className="space-y-1">
              <div className="flex justify-between text-[10px] font-mono text-muted-foreground">
                <span>Escala (Zoom da Peça)</span>
                <span>{presentationState.scale.toFixed(1)}x</span>
              </div>
              <input
                type="range"
                min={0.3}
                max={3.0}
                step={0.1}
                title="Zoom da Peça"
                value={presentationState.scale}
                onChange={(e) => handlePresentationChange({ scale: parseFloat(e.target.value) })}
                className="w-full h-1 bg-slate-800 rounded-lg appearance-none cursor-pointer accent-primary"
              />
            </div>

            {/* Plano de Corte */}
            <div className="space-y-2 pt-1 border-t border-slate-800">
              <div className="flex items-center justify-between">
                <span className="font-mono text-[10px] text-muted-foreground">Corte de Seção (Clipping)</span>
                <input
                  type="checkbox"
                  id="section-cuts-enable"
                  title="Habilitar Plano de Corte"
                  checked={presentationState.sectionEnabled}
                  onChange={(e) => handlePresentationChange({ sectionEnabled: e.target.checked })}
                  className="rounded border-slate-800 bg-slate-950 accent-primary cursor-pointer h-3.5 w-3.5"
                />
              </div>

              {presentationState.sectionEnabled && (
                <div className="space-y-3 animate-in fade-in slide-in-from-bottom-2 duration-150">
                  {/* Seletor Eixo */}
                  <div className="flex gap-2">
                    {(['x', 'y', 'z'] as const).map((ax) => (
                      <Button
                        key={ax}
                        size="sm"
                        variant={presentationState.sectionAxis === ax ? 'default' : 'outline'}
                        className="flex-1 h-7 text-[9px] font-mono uppercase"
                        onClick={() => handlePresentationChange({ sectionAxis: ax })}
                      >
                        Eixo {ax}
                      </Button>
                    ))}
                  </div>

                  {/* Slider de Nível */}
                  <div className="space-y-1">
                    <div className="flex justify-between text-[9px] font-mono text-muted-foreground">
                      <span>Posição do Corte</span>
                      <span>{(presentationState.sectionLevel * 100).toFixed(0)}%</span>
                    </div>
                    <input
                      type="range"
                      min={-0.5}
                      max={0.5}
                      step={0.01}
                      title="Nível de Corte"
                      value={presentationState.sectionLevel}
                      onChange={(e) => handlePresentationChange({ sectionLevel: parseFloat(e.target.value) })}
                      className="w-full h-1 bg-slate-800 rounded-lg appearance-none cursor-pointer accent-primary"
                    />
                  </div>

                  {/* Inverter Corte */}
                  <div className="flex items-center justify-between">
                    <label htmlFor="invert-section" className="text-[9px] font-mono text-muted-foreground cursor-pointer">
                      Inverter Direção do Corte
                    </label>
                    <input
                      type="checkbox"
                      id="invert-section"
                      title="Inverter Plano de Corte"
                      checked={presentationState.sectionInvert}
                      onChange={(e) => handlePresentationChange({ sectionInvert: e.target.checked })}
                      className="rounded border-slate-800 bg-slate-950 accent-primary cursor-pointer h-3 w-3"
                    />
                  </div>
                </div>
              )}
            </div>

            {/* Botão de Reset */}
            <Button
              variant="outline"
              size="sm"
              className="w-full h-8 font-mono text-[9px] gap-1.5"
              onClick={() => handlePresentationChange({
                rotation: [0, 0, 0],
                scale: 1,
                sectionEnabled: false,
                sectionAxis: 'y',
                sectionLevel: 0.0,
                sectionInvert: false
              })}
            >
              <RotateCw className="h-3 w-3" /> Resetar Apresentação
            </Button>

            {/* Botão de Apresentação no Viewer */}
            <Button
              variant="default"
              size="sm"
              className="w-full h-9 font-mono text-[10px] gap-1.5 bg-sky-500 hover:bg-sky-600 text-slate-950 font-bold glow-primary"
              onClick={() => navigate(`/viewer?room=${roomCode}`)}
            >
              <Box className="h-3.5 w-3.5" /> Manipular Peça no Viewer
            </Button>
          </div>
        )}

        {/* HUD Superior */}
        <div className="absolute top-4 left-4 right-4 pointer-events-none flex justify-between items-start z-10">
          <div className="pointer-events-auto flex items-center gap-2 rounded-lg border border-border bg-slate-900/90 backdrop-blur-md px-3.5 py-2 shadow-2xl">
            <Users className="h-4 w-4 text-primary" />
            <div className="flex flex-col">
              <span className="font-mono text-[9px] text-muted-foreground uppercase">Reunião Conectada</span>
              <span className="font-mono text-xs font-semibold text-foreground">
                Online: {activeUsersCount}/8
              </span>
            </div>
          </div>

          <div className="pointer-events-auto flex items-center gap-3">
            {/* Código da sala */}
            <div className="flex items-center gap-1.5 rounded-lg border border-border bg-slate-900/90 backdrop-blur-md px-3 py-1.5 shadow-2xl">
              <span className="font-mono text-[10px] text-muted-foreground">CÓDIGO:</span>
              <span className="font-mono text-xs font-bold text-primary tracking-widest">{roomCode}</span>
              <Button
                variant="ghost"
                size="icon"
                className="h-5 w-5 text-muted-foreground hover:text-foreground"
                onClick={() => {
                  navigator.clipboard.writeText(window.location.href);
                  toast.success('Link de convite copiado!');
                }}
                title="Copiar link do convite"
              >
                <Share2 className="h-3 w-3" />
              </Button>
            </div>

            {/* Sair */}
            <Button variant="destructive" size="sm" className="font-mono text-[10px] gap-1.5 h-8 px-3" onClick={handleLeaveRoom}>
              <LogOut className="h-3.5 w-3.5" /> Sair
            </Button>
          </div>
        </div>

        {/* HUD Inferior - Controles de Áudio & Modo Foco */}
        <div className="absolute bottom-4 left-4 pointer-events-none z-10 flex gap-2">
          <Button
            variant={isMuted ? 'destructive' : 'default'}
            size="icon"
            className="pointer-events-auto h-10 w-10 rounded-xl shadow-2xl border"
            onClick={() => setIsMuted(!isMuted)}
            title={isMuted ? 'Ativar microfone' : 'Mutar microfone'}
          >
            {isMuted ? <MicOff className="h-4.5 w-4.5" /> : <Mic className="h-4.5 w-4.5" />}
          </Button>

          <Button
            variant={isFocusMode ? 'secondary' : 'outline'}
            size="icon"
            className={`pointer-events-auto h-10 w-10 rounded-xl shadow-2xl border ${
              isFocusMode 
                ? 'bg-sky-500 hover:bg-sky-600 text-slate-950 border-sky-400' 
                : 'bg-slate-900/90 text-white border-slate-700 hover:bg-slate-800'
            }`}
            onClick={() => setIsFocusMode(!isFocusMode)}
            title={isFocusMode ? 'Voltar para Sala Virtual (Minimizar)' : 'Focar na Peça (Tela Cheia)'}
          >
            {isFocusMode ? <Minimize2 className="h-4.5 w-4.5" /> : <Maximize2 className="h-4.5 w-4.5" />}
          </Button>

          <div className="pointer-events-auto rounded-xl border bg-slate-900/90 backdrop-blur-md px-4 py-2 flex flex-col justify-center shadow-2xl">
            <span className="font-mono text-[8px] text-muted-foreground uppercase">
              {isPresenter ? 'Apresentação Ativa' : 'Observador'}
            </span>
            <span className="text-[10px] text-foreground font-mono">
              {isPresenter 
                ? 'Você está transmitindo os cortes e rotações da maquete.' 
                : 'Aguarde as rotações e planos de corte efetuados pelo Host.'}
            </span>
          </div>
        </div>
      </div>

      {/* Painel Lateral Direito (Abas Chat / Participantes) */}
      <div className="w-80 border-l border-slate-800 bg-slate-900/95 flex flex-col h-full z-10 shadow-2xl">
        {/* Seletor de Abas */}
        <div className="flex border-b border-slate-800 bg-slate-950/40">
          <Button
            variant="ghost"
            className={`flex-1 rounded-none border-b-2 font-mono text-[10px] uppercase h-12 gap-1.5 ${
              activeTab === 'participants' ? 'border-primary text-primary bg-slate-900/40' : 'border-transparent text-muted-foreground'
            }`}
            onClick={() => setActiveTab('participants')}
          >
            <Users className="h-3.5 w-3.5" /> Membros ({activeUsersCount})
          </Button>
          <Button
            variant="ghost"
            className={`flex-1 rounded-none border-b-2 font-mono text-[10px] uppercase h-12 gap-1.5 ${
              activeTab === 'chat' ? 'border-primary text-primary bg-slate-900/40' : 'border-transparent text-muted-foreground'
            }`}
            onClick={() => setActiveTab('chat')}
          >
            <MessageSquare className="h-3.5 w-3.5" /> Chat
          </Button>
        </div>

        {/* ABA PARTICIPANTES */}
        {activeTab === 'participants' && (
          <div className="flex-1 overflow-y-auto p-4 space-y-3 scrollbar-thin">
            <span className="font-mono text-[9px] text-muted-foreground uppercase tracking-widest block mb-2">Quem está na sala</span>
            
            <div className="space-y-2.5">
              {Object.keys(mergedPeers).map((chairKey) => {
                const peer = mergedPeers[chairKey];
                const isHost = peer.role === 'presenter';
                const isMe = peer.chairId === selectedChair;

                return (
                  <div key={peer.presence_ref || 'local'} className="rounded-lg border border-slate-800 bg-slate-950/40 p-3 flex items-start gap-3 relative overflow-hidden">
                    {/* Indicador da cor do avatar do Mii via classe estática Tailwind */}
                    <div className={`h-8 w-8 rounded-full border border-slate-800 flex items-center justify-center font-bold text-xs ${getAvatarBgClass(peer.avatarId)}`}>
                      {peer.username.substring(0, 2).toUpperCase()}
                    </div>
                    
                    {/* Detalhes do Usuário */}
                    <div className="flex-1 min-w-0">
                      <div className="flex items-center gap-1.5">
                        <span className="font-mono text-xs font-bold text-slate-100 truncate block">
                          {peer.username} {isMe && '(Você)'}
                        </span>
                        
                        {isHost && (
                          <span className="text-[8px] font-mono bg-primary/20 text-primary px-1.5 py-0.5 rounded uppercase font-semibold">
                            Host
                          </span>
                        )}
                      </div>

                      {/* Cargo e Empresa */}
                      <span className="font-mono text-[9.5px] text-muted-foreground block truncate mt-0.5 uppercase">
                        💼 {peer.cargo}
                      </span>
                      <span className="font-mono text-[9px] text-primary/75 block truncate uppercase">
                        🏢 {peer.empresa}
                      </span>
                    </div>

                    <div className="absolute top-2 right-2.5 font-mono text-[8px] text-slate-600">
                      Chair {peer.chairId}
                    </div>
                  </div>
                );
              })}
            </div>
          </div>
        )}

        {/* ABA CHAT */}
        {activeTab === 'chat' && (
          <>
            <div ref={chatScrollRef} className="flex-1 overflow-y-auto p-4 space-y-3 scrollbar-thin">
              {chatMessages.length === 0 ? (
                <div className="h-full flex flex-col items-center justify-center text-slate-500 text-center px-4 space-y-2">
                  <MessageSquare className="h-8 w-8 opacity-30 text-primary" />
                  <p className="text-[10px] font-mono leading-relaxed">
                    Nenhuma mensagem enviada. Seja o primeiro a digitar no chat da reunião!
                  </p>
                </div>
              ) : (
                chatMessages.map((msg) => (
                  <div key={msg.id} className="space-y-0.5">
                    <div className="flex items-baseline justify-between">
                      <span className="font-mono text-[10px] font-bold text-primary uppercase">{msg.sender}</span>
                      <span className="text-[8px] text-slate-500 font-mono">{msg.time}</span>
                    </div>
                    <p className="text-xs bg-slate-800/60 border border-slate-700/30 rounded-lg p-2 leading-relaxed text-slate-300">
                      {msg.text}
                    </p>
                  </div>
                ))
              )}
            </div>

            {/* Input do Chat */}
            <div className="p-3 border-t border-slate-800 bg-slate-900 flex gap-2">
              <Input
                type="text"
                placeholder="Digite sua mensagem..."
                value={newMessage}
                onChange={(e) => setNewMessage(e.target.value)}
                onKeyDown={(e) => {
                  if (e.key === 'Enter') handleSendMessage();
                }}
                className="flex-1 text-xs border-slate-800 bg-slate-950/65"
              />
              <Button variant="default" size="icon" className="h-9 w-9 bg-primary" onClick={handleSendMessage}>
                <Send className="h-3.5 w-3.5" />
              </Button>
            </div>
          </>
        )}
      </div>
    </div>
  );
}
