import { useNavigate, useSearchParams } from "react-router-dom";
import { supabase } from "@/integrations/supabase/client";
import { ArrowLeft, Glasses, Box, Ruler, FileText, Upload, Loader2, Users, Menu, Target } from "lucide-react";
import { Button } from "@/components/ui/button";
import { useModelStore } from "@/stores/useModelStore";
import { ModelViewerCanvas } from "@/components/three/ModelViewer";
import { ViewerControls } from "@/components/ViewerControls";
import { InspectionChecklist } from "@/components/InspectionChecklist";
import { FineTuningControls } from "@/components/FineTuningControls";
import { MeasurementsList } from "@/components/MeasurementsList";
import { ScreenshotGallery } from "@/components/ScreenshotGallery";
import { ViewCube } from "@/components/ViewCube";
import { SectionCutPanel } from "@/components/SectionCutPanel";
import { ShareButton } from "@/components/ShareButton";
import { CloudLoader } from "@/components/CloudLoader";
import { SceneModelList } from "@/components/SceneModelList";
import { useEffect, useRef, useCallback, useState } from "react";
import { toast } from "sonner";
import { ScrollArea } from "@/components/ui/scroll-area";
import { Separator } from "@/components/ui/separator";
import { getSupportedExtension, convertToGLB, ACCEPTED_EXTENSIONS } from "@/lib/convertToGLB";
import { validateModelFile } from "@/lib/validateModelFile";
import { convertIFCtoGLB } from "@/lib/convertIFC";
import { mainCameraRef, mainControlsRef } from "@/components/three/viewCubeBus";

const Viewer = () => {
  const navigate = useNavigate();
  const {
    model,
    xrSupported,
    addModel,
    models,
    maxModels,
    scaleRatio,
    fineTuning,
    sectionEnabled,
    sectionInvert,
    sectionLevel,
    hoverIfcProps
  } = useModelStore();
  const fileInputRef = useRef<HTMLInputElement>(null);
  const [converting, setConverting] = useState(false);

  const [isFullscreen, setIsFullscreen] = useState(false);
  const [sidebarOpen, setSidebarOpen] = useState(true);

  useEffect(() => {
    const handleFullscreenChange = () => {
      setIsFullscreen(!!document.fullscreenElement);
    };
    document.addEventListener("fullscreenchange", handleFullscreenChange);
    return () => {
      document.removeEventListener("fullscreenchange", handleFullscreenChange);
    };
  }, []);

  const handleRecenter = useCallback(() => {
    const camera = mainCameraRef.current;
    const controls = mainControlsRef.current;
    if (camera) {
      camera.position.set(2, 2, 2);
      camera.up.set(0, 1, 0);
      camera.lookAt(0, 0, 0);
    }
    if (controls) {
      // @ts-ignore
      controls.target.set(0, 0, 0);
      // @ts-ignore
      controls.update();
    }
    toast.success("Visualização centralizada");
  }, []);

  const exitFullscreen = useCallback(() => {
    if (document.fullscreenElement) {
      document.exitFullscreen().catch((err) => {
        console.error("Erro ao sair de tela cheia:", err);
      });
    }
  }, []);

  const [searchParams] = useSearchParams();
  const roomId = searchParams.get("room");
  const channelRef = useRef<ReturnType<typeof supabase.channel> | null>(null);

  // Se não houver modelo e não estivermos em Reunião, volta para a Home
  useEffect(() => {
    if (!model && !roomId) {
      navigate("/");
    }
  }, [model, roomId, navigate]);

  const sendMeetingUpdate = useCallback((ft: typeof fineTuning, secEn: typeof sectionEnabled, secLevel: typeof sectionLevel, secInv: typeof sectionInvert) => {
    if (!roomId || !channelRef.current) return;

    const enabledAxis = (['x', 'y', 'z'] as const).find(ax => secEn[ax]);
    const isSectionActive = !!enabledAxis;
    const sectionAxis = enabledAxis || 'y';
    const sectionLevelVal = isSectionActive ? secLevel[sectionAxis] : 0.0;
    const sectionInvertVal = isSectionActive ? secInv[sectionAxis] : false;

    // Obtém dados da maquete ativa na store
    const activeModelStore = useModelStore.getState().model;

    const payload = {
      rotation: [ft.rotX, ft.rotY, ft.rotZ],
      scale: ft.scale,
      sectionEnabled: isSectionActive,
      sectionAxis,
      sectionLevel: sectionLevelVal,
      sectionInvert: sectionInvertVal,
      modelUrl: activeModelStore?.url,
      modelFileName: activeModelStore?.fileName,
      modelFileSize: activeModelStore?.fileSize
    };

    console.log("📡 [Viewer Meeting Sync] Enviando atualização de apresentação:", payload);
    channelRef.current.send({
      type: 'broadcast',
      event: 'presentation_update',
      payload
    });
  }, [roomId]);

  // Conecta ao canal do Supabase se o Viewer foi aberto no modo Reunião
  useEffect(() => {
    if (!roomId) return;

    const finalRoomId = roomId.trim().toUpperCase();
    console.log(`🔌 [Viewer Meeting Sync] Conectando ao canal da reunião: ${finalRoomId}`);

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

    channelRef.current = channel;

    channel.subscribe((status) => {
      console.log(`🔌 [Viewer Meeting Sync] Status do canal: ${status}`);
      if (status === 'SUBSCRIBED') {
        const state = useModelStore.getState();
        sendMeetingUpdate(state.fineTuning, state.sectionEnabled, state.sectionLevel, state.sectionInvert);
      }
    });

    return () => {
      console.log(`🔌 [Viewer Meeting Sync] Desconectando do canal da reunião: ${finalRoomId}`);
      channel.unsubscribe();
      supabase.removeChannel(channel);
    };
  }, [roomId, sendMeetingUpdate]);

  // Observa mudanças primitivas nas ferramentas 3D para propagação imediata via Broadcast
  const rotX = fineTuning.rotX;
  const rotY = fineTuning.rotY;
  const rotZ = fineTuning.rotZ;
  const scaleVal = fineTuning.scale;
  
  const secEnabledX = sectionEnabled.x;
  const secEnabledY = sectionEnabled.y;
  const secEnabledZ = sectionEnabled.z;
  
  const secLevelX = sectionLevel.x;
  const secLevelY = sectionLevel.y;
  const secLevelZ = sectionLevel.z;
  
  const secInvertX = sectionInvert.x;
  const secInvertY = sectionInvert.y;
  const secInvertZ = sectionInvert.z;

  const activeModelFileName = model?.fileName;

  useEffect(() => {
    if (!roomId || !channelRef.current) return;
    sendMeetingUpdate(fineTuning, sectionEnabled, sectionLevel, sectionInvert);
  }, [
    roomId,
    rotX,
    rotY,
    rotZ,
    scaleVal,
    secEnabledX,
    secEnabledY,
    secEnabledZ,
    secLevelX,
    secLevelY,
    secLevelZ,
    secInvertX,
    secInvertY,
    secInvertZ,
    activeModelFileName,
    sendMeetingUpdate,
    fineTuning,
    sectionEnabled,
    sectionLevel,
    sectionInvert
  ]);

  const handleFileUpload = useCallback(async (e: React.ChangeEvent<HTMLInputElement>) => {
    const file = e.target.files?.[0];
    e.target.value = '';
    if (!file) return;
    if (models.length >= maxModels) {
      toast.error(`Limite de ${maxModels} peças simultâneas atingido`);
      return;
    }
    const ext = getSupportedExtension(file.name);
    if (!ext) {
      toast.error('Formato inválido. Selecione .GLB, .OBJ, .STL ou .IFC');
      return;
    }
    const sizeCheck = validateModelFile(file.name, file.size, ext);
    if (!sizeCheck.ok) {
      toast.error(sizeCheck.reason!);
      return;
    }
    if (ext === 'glb') {
      try {
        const head = await file.slice(0, 16).arrayBuffer();
        const sig = validateModelFile(file.name, file.size, ext, head);
        if (!sig.ok) {
          toast.error(sig.reason!);
          return;
        }
      } catch (err) {
        console.error('[upload] header read failed', err);
      }
      const url = URL.createObjectURL(file);
      addModel({ fileName: file.name, fileSize: file.size, url });
      toast.success(`"${file.name}" adicionado à cena`);
      return;
    }
    setConverting(true);
    try {
      const buffer = await file.arrayBuffer();
      const sig = validateModelFile(file.name, file.size, ext, buffer);
      if (!sig.ok) {
        toast.error(sig.reason!);
        if (sig.detail) console.warn('[validateModelFile]', sig.detail);
        return;
      }
      const result = ext === 'ifc'
        ? await convertIFCtoGLB(buffer, file.name)
        : await convertToGLB(buffer, ext, file.name);
      const url = URL.createObjectURL(result.blob);
      addModel({ fileName: result.fileName, fileSize: result.fileSize, url });
      toast.success(`"${file.name}" convertido e adicionado!`);
    } catch (err) {
      console.error('[upload] conversion failed', err);
      const msg = err instanceof Error ? err.message : 'erro desconhecido';
      toast.error(`Falha ao converter "${file.name}": ${msg}`);
    } finally {
      setConverting(false);
    }
  }, [addModel, models.length, maxModels]);

  // Removido o bloqueio para permitir carregamento de modelo na sala

  const [enteringXR, setEnteringXR] = useState(false);

  const handleEnterXR = useCallback(async () => {
    if (!xrSupported) {
      toast.error("WebXR não é suportado neste navegador. Use o navegador do Meta Quest 3.");
      return;
    }
    setEnteringXR(true);

    // Timeout de segurança — se não entrar em 15s, cancela
    const timeoutId = setTimeout(() => {
      setEnteringXR(false);
      toast.error("Tempo limite ao iniciar modo AR. Verifique se o Meta Quest Browser está conectado.");
    }, 15000);

    try {
      const { xrStore } = await import('@/stores/useXRStore');
      // Marca que está entrando no AR antes de navegar — bloqueia auto-return prematuro
      (window as unknown as { __setXrEntering?: (v: boolean) => void }).__setXrEntering?.(true);
      await xrStore.enterAR();
      clearTimeout(timeoutId);
      navigate("/xr");
    } catch (e) {
      clearTimeout(timeoutId);
      setEnteringXR(false);
      (window as unknown as { __setXrEntering?: (v: boolean) => void }).__setXrEntering?.(false);
      console.error('[Viewer] XR enterAR error:', e);
      toast.error("Falha ao iniciar modo AR. Verifique se o Meta Quest Browser está conectado.");
    }
  }, [xrSupported, navigate]);

  const handleEnterMeeting = () => {
    // Coleta o eixo habilitado de seção no Viewer
    const enabledAxis = (['x', 'y', 'z'] as const).find(ax => sectionEnabled[ax]);
    const isSectionActive = !!enabledAxis;
    const sectionAxis = enabledAxis || 'y';
    const sectionLevelVal = isSectionActive ? sectionLevel[sectionAxis] : 0.0;
    const sectionInvertVal = isSectionActive ? sectionInvert[sectionAxis] : false;

    // Salva o estado atual da peça
    const initialMeetingState = {
      rotation: [fineTuning.rotX, fineTuning.rotY, fineTuning.rotZ],
      scale: fineTuning.scale,
      sectionEnabled: isSectionActive,
      sectionAxis,
      sectionLevel: sectionLevelVal,
      sectionInvert: sectionInvertVal
    };

    localStorage.setItem('tsxr_initial_meeting_state', JSON.stringify(initialMeetingState));
    toast.success('Configurações da maquete salvas. Direcionando para a reunião...');
    navigate('/meeting');
  };

  const canAddMore = models.length < maxModels;

  return (
    <div className="flex h-screen flex-col bg-background">
      <input
        ref={fileInputRef}
        type="file"
        accept={ACCEPTED_EXTENSIONS}
        className="hidden"
        title="Selecionar arquivo de maquete para upload"
        placeholder="Upload de maquete"
        onChange={handleFileUpload}
      />

      {/* Top bar */}
      <header className="flex items-center justify-between border-b bg-card px-4 py-3">
        <div className="flex items-center gap-3">
          <Button
            variant="ghost"
            size={roomId ? "default" : "icon"}
            className={roomId ? "gap-1.5 px-3 text-xs font-mono h-9 hover:bg-slate-800" : ""}
            onClick={() => roomId ? navigate(`/meeting/${roomId}`) : navigate("/")}
          >
            <ArrowLeft className="h-4 w-4" />
            {roomId && "Voltar para Sala"}
          </Button>
          <div className="flex items-center gap-2">
            <Box className="h-5 w-5 text-primary" />
            <h1 className="font-mono text-sm font-semibold text-foreground">
              Steel<span className="text-primary">XR</span>
            </h1>
          </div>
        </div>

        <div className="flex items-center gap-2">
          <Button
            variant="outline"
            className="gap-2 border-primary/30 hover:bg-primary/10 text-primary font-mono h-9"
            onClick={handleEnterMeeting}
          >
            <Users className="h-4 w-4" />
            Reunião Virtual
          </Button>
          <ShareButton />
          <Button className="gap-2 glow-primary h-9" disabled={!xrSupported || enteringXR} onClick={handleEnterXR}>
            {enteringXR ? <Loader2 className="h-4 w-4 animate-spin" /> : <Glasses className="h-4 w-4" />}
            {enteringXR ? 'Iniciando AR…' : 'Entrar em Modo XR'}
          </Button>
        </div>
      </header>

      <div className="flex flex-1 overflow-hidden">
        {/* 3D Canvas with floating controls */}
        <div className="relative flex-1 min-w-0" id="canvas-container">
          <ModelViewerCanvas />
          {hoverIfcProps && (
            <div 
              className={`absolute left-4 z-40 w-72 rounded-xl border border-primary/20 bg-background/80 p-3.5 shadow-2xl backdrop-blur-md transition-all duration-300 pointer-events-none select-none font-mono text-[11px] ${
                isFullscreen ? 'top-16' : 'top-4'
              }`}
            >
              <div className="flex flex-col gap-2.5">
                <div className="flex items-center gap-1.5 border-b border-primary/10 pb-1.5">
                  <span className="h-1.5 w-1.5 rounded-full bg-primary animate-pulse" />
                  <span className="font-semibold text-primary uppercase text-[9px] tracking-wider font-sans">Propriedades IFC</span>
                </div>
                
                {Object.entries(hoverIfcProps).map(([key, value]) => {
                  if (!value) return null;
                  let displayKey = key;
                  if (key === 'name') displayKey = 'Nome';
                  else if (key === 'tag') displayKey = 'Marca';
                  else if (key === 'material') displayKey = 'Material';
                  else if (key === 'objectType') displayKey = 'Tipo';
                  else if (key === 'description') displayKey = 'Descrição';
                  
                  return (
                    <div key={key} className="flex flex-col gap-0.5">
                      <span className="text-[8px] text-muted-foreground uppercase tracking-widest">{displayKey}</span>
                      <span className="text-foreground font-semibold truncate text-[11px] max-w-[250px]" title={value}>{value}</span>
                    </div>
                  );
                })}
              </div>
            </div>
          )}
          {isFullscreen ? (
            <div className="absolute top-4 left-4 z-50 flex gap-2">
              <Button
                variant="outline"
                className="gap-2 bg-background/80 border-primary/40 hover:bg-primary/20 text-foreground font-mono shadow-md backdrop-blur-sm h-9"
                onClick={handleRecenter}
              >
                <Target className="h-4 w-4 text-primary animate-pulse" />
                Centralizar
              </Button>
              <Button
                variant="outline"
                className="gap-2 bg-background/80 border-destructive/40 hover:bg-destructive/20 text-foreground font-mono shadow-md backdrop-blur-sm h-9"
                onClick={exitFullscreen}
              >
                <ArrowLeft className="h-4 w-4 text-destructive" />
                Retornar (ESC)
              </Button>
            </div>
          ) : (
            <>
              {/* Botão de Expandir Sidebar (visível apenas se recolhido) */}
              {!sidebarOpen && (
                <Button
                  variant="outline"
                  size="icon"
                  onClick={() => setSidebarOpen(true)}
                  className="absolute right-4 top-[205px] z-30 h-8 w-8 rounded-md bg-background/80 border-primary/30 text-primary shadow-md hover:bg-primary/10"
                  title="Expandir menu"
                >
                  <Menu className="h-4 w-4" />
                </Button>
              )}

              <ViewCube />
              <ViewerControls />
              <SectionCutPanel />
            </>
          )}
        </div>

        {/* Side panel */}
        <aside className={`transition-all duration-300 shrink-0 border-l bg-card flex flex-col ${sidebarOpen ? 'w-80 opacity-100' : 'w-0 opacity-0 pointer-events-none border-l-0 overflow-hidden'}`}>
          <ScrollArea className="h-full">
            <div className="p-4 space-y-5">
              <div>
                <div className="flex items-center justify-between mb-3">
                  <h2 className="font-mono text-xs font-semibold uppercase tracking-widest text-muted-foreground">
                    Cena · {models.length}/{maxModels} peças
                  </h2>
                  <Button
                    variant="ghost"
                    size="icon"
                    className="h-6 w-6 text-muted-foreground hover:text-foreground hover:bg-muted"
                    onClick={() => setSidebarOpen(false)}
                    title="Recolher menu"
                  >
                    <Menu className="h-4 w-4" />
                  </Button>
                </div>
                <SceneModelList />
                <div className="mt-2 grid grid-cols-2 gap-1.5">
                  <Button
                    variant="outline"
                    size="sm"
                    className="h-8 gap-1.5 text-[10px] font-mono"
                    onClick={() => fileInputRef.current?.click()}
                    disabled={!canAddMore || converting}
                    title={canAddMore ? 'Adicionar arquivo local' : 'Limite atingido'}
                  >
                    {converting ? <Loader2 className="h-3.5 w-3.5 animate-spin" /> : <Upload className="h-3.5 w-3.5" />}
                    {converting ? 'Convertendo…' : 'Adicionar'}
                  </Button>
                  <CloudLoader compact variant="outline" />
                </div>
              </div>

              <Separator />

              <div>
                <h2 className="mb-2 font-mono text-xs font-semibold uppercase tracking-widest text-muted-foreground">
                  Peça selecionada
                </h2>
                {model ? (
                  <div className="space-y-3">
                    <InfoItem icon={FileText} label="Arquivo" value={model.fileName} />
                    <InfoItem icon={Box} label="Tamanho" value={`${(model.fileSize / (1024 * 1024)).toFixed(2)} MB`} />
                    <InfoItem icon={Ruler} label="Escala" value={`${scaleRatio.label} (mm)`} />
                  </div>
                ) : (
                  <div className="rounded-lg border border-dashed border-muted p-4 text-center bg-muted/20">
                    <p className="font-mono text-xs text-muted-foreground">Nenhuma peça ativa na cena</p>
                  </div>
                )}
              </div>

              <Separator />

              <FineTuningControls />

              <Separator />

              <MeasurementsList />

              <Separator />

              <InspectionChecklist />

              <Separator />

              <ScreenshotGallery />
              <div className="rounded-lg border bg-muted/50 p-3">
                <p className="font-mono text-xs text-muted-foreground">
                  Clique em uma peça na cena para selecioná-la — os controles de ajuste fino
                  passam a operar sobre ela. Use "Adicionar" / "Nuvem" para empilhar peças.
                </p>
              </div>
            </div>
          </ScrollArea>
        </aside>
      </div>
    </div>
  );
};

function InfoItem({ icon: Icon, label, value }: { icon: React.ComponentType<{ className?: string }>; label: string; value: string }) {
  return (
    <div className="flex items-start gap-3">
      <Icon className="mt-0.5 h-4 w-4 shrink-0 text-primary" />
      <div className="min-w-0">
        <p className="text-xs text-muted-foreground">{label}</p>
        <p className="truncate font-mono text-sm text-foreground">{value}</p>
      </div>
    </div>
  );
}

export default Viewer;
