import { useState, useCallback } from 'react';
import { Cloud, Loader2, Link2 } from 'lucide-react';
import { Button } from '@/components/ui/button';
import {
  Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, DialogTrigger,
} from '@/components/ui/dialog';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { useModelStore } from '@/stores/useModelStore';
import { toast } from 'sonner';
import { getSupportedExtension, convertToGLB } from '@/lib/convertToGLB';
import { convertIFCtoGLB } from '@/lib/convertIFC';
import { validateModelFile } from '@/lib/validateModelFile';
import { addRecentFile } from '@/lib/recentFiles';

const DEFAULT_URL = 'https://store.tracksteel.com.br/demo.ifc';

const PRESETS: { label: string; url: string }[] = [
  { label: 'Demo IFC (TrackSteel)', url: DEFAULT_URL },
];

/** Normaliza URLs de Dropbox / OneDrive para apontar ao binário direto. */
function normalizeCloudUrl(input: string): string {
  try {
    const u = new URL(input);
    if (/(^|\.)dropbox\.com$/.test(u.hostname)) {
      u.searchParams.set('dl', '1');
      return u.toString();
    }
    if (/(^|\.)1drv\.ms$|onedrive\.live\.com$/.test(u.hostname)) {
      u.searchParams.set('download', '1');
      return u.toString();
    }
    return input;
  } catch {
    return input;
  }
}

/** Tenta obter um token JWT de uma instância FileBrowser NoAuth (POST /api/login vazio). */
async function tryFileBrowserToken(origin: string): Promise<string | null> {
  try {
    const r = await fetch(`${origin}/api/login`, { method: 'POST', mode: 'cors' });
    if (!r.ok) return null;
    const txt = (await r.text()).trim();
    // FileBrowser devolve o JWT como texto puro
    if (txt && txt.split('.').length === 3) return txt;
    return null;
  } catch {
    return null;
  }
}

/** Faz fetch tentando vários endpoints típicos de hosts que servem SPA (FileBrowser etc.). */
async function smartFetch(rawUrl: string): Promise<Response> {
  const url = normalizeCloudUrl(rawUrl.trim());
  let res = await fetch(url, { mode: 'cors' });
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
  const ct = res.headers.get('content-type') || '';
  if (!ct.includes('text/html')) return res;

  // Servidor devolveu HTML — tentamos endpoints binários do FileBrowser
  const u = new URL(url);
  const path = u.pathname.startsWith('/api/raw/') ? u.pathname : `/api/raw${u.pathname}`;

  // 1ª tentativa: /api/raw/... cru
  try {
    const r = await fetch(`${u.origin}${path}${u.search}`, { mode: 'cors' });
    if (r.ok && !(r.headers.get('content-type') || '').includes('text/html')) return r;
    if (r.status !== 401) {
      // pode ser outro erro — segue para fluxo de token
    }
  } catch { /* continua */ }

  // 2ª tentativa: pega token JWT NoAuth e usa ?auth=
  const token = await tryFileBrowserToken(u.origin);
  if (token) {
    const sep = u.search ? '&' : '?';
    const r = await fetch(`${u.origin}${path}${u.search}${sep}auth=${encodeURIComponent(token)}`, { mode: 'cors' });
    if (r.ok && !(r.headers.get('content-type') || '').includes('text/html')) return r;
  }

  throw new Error(
    'O servidor devolveu HTML. Use um link DIRETO do arquivo (ex.: Dropbox ?dl=1, OneDrive ?download=1, ' +
    'ou habilite endpoint público no FileBrowser).'
  );
}

interface CloudLoaderProps {
  /** Renderiza como botão compacto (para HUD do AR) */
  compact?: boolean;
  /** Variante visual do botão */
  variant?: 'default' | 'outline';
  className?: string;
}

export function CloudLoader({ compact = false, variant = 'outline', className }: CloudLoaderProps) {
  const addModel = useModelStore((s) => s.addModel);
  const modelsCount = useModelStore((s) => s.models.length);
  const maxModels = useModelStore((s) => s.maxModels);
  const [open, setOpen] = useState(false);
  const [url, setUrl] = useState(DEFAULT_URL);
  const [loading, setLoading] = useState(false);

  const handleLoad = useCallback(async (rawUrl: string) => {
    if (!rawUrl) return;
    if (modelsCount >= maxModels) {
      toast.error(`Limite de ${maxModels} peças simultâneas atingido. Remova uma antes de adicionar outra.`);
      return;
    }
    setLoading(true);
    try {
      const fileName = rawUrl.split('/').pop()?.split('?')[0] || 'modelo-cloud';
      const ext = getSupportedExtension(fileName);
      if (!ext) {
        toast.error('URL deve apontar para .GLB, .OBJ, .STL ou .IFC');
        return;
      }

      const response = await smartFetch(rawUrl);
      const buffer = await response.arrayBuffer();

      // Valida tamanho + assinatura antes de converter
      const sig = validateModelFile(fileName, buffer.byteLength, ext, buffer);
      if (!sig.ok) {
        toast.error(sig.reason!);
        if (sig.detail) console.warn('[validateModelFile]', sig.detail);
        return;
      }

      let blob: Blob, outName = fileName, outSize = buffer.byteLength;
      if (ext === 'glb') {
        blob = new Blob([buffer], { type: 'model/gltf-binary' });
      } else if (ext === 'ifc') {
        const r = await convertIFCtoGLB(buffer, fileName);
        blob = r.blob; outName = r.fileName; outSize = r.fileSize;
      } else {
        const r = await convertToGLB(buffer, ext, fileName);
        blob = r.blob; outName = r.fileName; outSize = r.fileSize;
      }
      const blobUrl = URL.createObjectURL(blob);
      addModel({ fileName: outName, fileSize: outSize, url: blobUrl });
      addRecentFile(outName, blob).catch(() => {});
      toast.success(`"${outName}" adicionado à cena`);
      setOpen(false);
    } catch (err) {
      console.error(err);
      toast.error(err instanceof Error ? err.message : 'Falha ao carregar da nuvem (verifique URL/CORS)');
    } finally {
      setLoading(false);
    }
  }, [addModel, modelsCount, maxModels]);

  return (
    <Dialog open={open} onOpenChange={setOpen}>
      <DialogTrigger asChild>
        {compact ? (
          <Button variant={variant} size="sm" className={`h-8 gap-1.5 text-[10px] font-mono ${className ?? ''}`} title="Carregar da Nuvem">
            <Cloud className="h-3.5 w-3.5" />
            Nuvem
          </Button>
        ) : (
          <Button
            variant={variant}
            className={`h-12 w-full gap-2 border-primary/40 text-primary hover:border-primary hover:bg-primary/10 transition-all text-xs ${className ?? ''}`}
          >
            <Cloud className="h-4 w-4" />
            Carregar da Nuvem
          </Button>
        )}
      </DialogTrigger>
      <DialogContent className="sm:max-w-md">
        <DialogHeader>
          <DialogTitle className="flex items-center gap-2">
            <Cloud className="h-4 w-4 text-primary" />
            Carregar modelo da nuvem
          </DialogTitle>
          <DialogDescription className="text-xs">
            URL direta para .GLB, .OBJ, .STL ou .IFC. Dropbox use <code>?dl=1</code>, OneDrive <code>?download=1</code>.
            FileBrowser é detectado automaticamente.
          </DialogDescription>
        </DialogHeader>

        <div className="space-y-3">
          <div className="space-y-1.5">
            <Label htmlFor="cloud-url" className="text-xs font-mono">URL do modelo</Label>
            <div className="flex gap-2">
              <Link2 className="h-4 w-4 text-muted-foreground mt-2.5 shrink-0" />
              <Input
                id="cloud-url"
                value={url}
                onChange={(e) => setUrl(e.target.value)}
                placeholder="https://exemplo.com/modelo.glb"
                disabled={loading}
                className="font-mono text-xs"
              />
            </div>
          </div>

          {PRESETS.length > 0 && (
            <div className="space-y-1.5">
              <Label className="text-xs font-mono text-muted-foreground">Templates prontos</Label>
              <div className="flex flex-wrap gap-1.5">
                {PRESETS.map((p) => (
                  <Button
                    key={p.url}
                    variant="ghost"
                    size="sm"
                    className="h-7 text-[10px] font-mono border border-border"
                    disabled={loading}
                    onClick={() => setUrl(p.url)}
                  >
                    {p.label}
                  </Button>
                ))}
              </div>
            </div>
          )}
        </div>

        <DialogFooter>
          <Button variant="ghost" onClick={() => setOpen(false)} disabled={loading}>Cancelar</Button>
          <Button onClick={() => handleLoad(url.trim())} disabled={loading || !url.trim()} className="gap-2">
            {loading ? <Loader2 className="h-4 w-4 animate-spin" /> : <Cloud className="h-4 w-4" />}
            {loading ? 'Baixando…' : 'Carregar'}
          </Button>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  );
}
