"use client";

import { useAction } from "convex/react";
import { api } from "@/convex/_generated/api";
import { useCallback, useRef, useState } from "react";
import { cn } from "@/lib/utils";
import { Spinner } from "@/components/ui/spinner";
import { Upload } from "lucide-react";
import { Progress } from "@/components/ui/progress";

type Uploaded = { storageId: string; name: string; size?: number; type?: string; previewUrl?: string };

export function Dropzone({
  onUploaded,
  maxFiles = 5,
  maxSize = 10 * 1024 * 1024,
  multiple = true,
  className,
}: {
  onUploaded?: (files: Uploaded[]) => void;
  maxFiles?: number;
  maxSize?: number;
  multiple?: boolean;
  className?: string;
}) {
  const generateUrl = useAction(api.files.generateUploadUrl);
  const inputRef = useRef<HTMLInputElement>(null);
  const [drag, setDrag] = useState(false);
  const [items, setItems] = useState<Array<{ id: string; name: string; progress: number; status: "idle" | "uploading" | "done" | "error" }>>([]);

  const startUpload = useCallback(async (files: FileList | File[]) => {
    const list = Array.from(files).slice(0, maxFiles);
    const uploaded: Uploaded[] = [];
    for (const file of list) {
      if (file.size > maxSize) continue;
      const url = await generateUrl({});
      const id = `${file.name}-${file.size}-${Date.now()}`;
      const localPreview = file.type.startsWith("image/") ? URL.createObjectURL(file) : undefined;
      setItems((prev) => [...prev, { id, name: file.name, progress: 0, status: "uploading" }]);
      await new Promise<void>((resolve) => {
        const xhr = new XMLHttpRequest();
        xhr.open("POST", url);
        if (file.type) {
          xhr.setRequestHeader("Content-Type", file.type);
        }
        xhr.upload.onprogress = (e) => {
          if (!e.lengthComputable) return;
          const progress = Math.round((e.loaded / e.total) * 100);
          setItems((prev) => prev.map((it) => (it.id === id ? { ...it, progress } : it)));
        };
        xhr.onload = () => {
          try {
            const res = JSON.parse(xhr.responseText);
            if (res?.storageId) {
              uploaded.push({ storageId: res.storageId, name: file.name, size: file.size, type: file.type, previewUrl: localPreview });
              setItems((prev) => prev.map((it) => (it.id === id ? { ...it, progress: 100, status: "done" } : it)));
            } else {
              setItems((prev) => prev.map((it) => (it.id === id ? { ...it, status: "error" } : it)));
            }
          } catch {
            setItems((prev) => prev.map((it) => (it.id === id ? { ...it, status: "error" } : it)));
          }
          resolve();
        };
        xhr.onerror = () => {
          setItems((prev) => prev.map((it) => (it.id === id ? { ...it, status: "error" } : it)));
          resolve();
        };
        xhr.send(file);
      });
    }
    if (uploaded.length) onUploaded?.(uploaded);
  }, [generateUrl, maxFiles, maxSize, onUploaded]);

  return (
    <div className={cn("space-y-3", className)}>
      <div
        role="button"
        tabIndex={0}
        className={cn(
          "group relative rounded-xl border border-dashed border-black/30 bg-white p-6 text-center transition-all focus:outline-none focus:ring-2 focus:ring-[#00d6eb]/40 focus:ring-offset-2",
          drag ? "border-black bg-black/5" : "hover:border-black hover:bg-black/5"
        )}
        onClick={() => inputRef.current?.click()}
        onKeyDown={(event) => {
          if (event.key === "Enter" || event.key === " ") {
            event.preventDefault()
            inputRef.current?.click()
          }
        }}
        onDragEnter={(e) => { e.preventDefault(); setDrag(true); }}
        onDragOver={(e) => { e.preventDefault(); setDrag(true); }}
        onDragLeave={(e) => { e.preventDefault(); setDrag(false); }}
        onDrop={(e) => { e.preventDefault(); setDrag(false); startUpload(e.dataTransfer.files); }}
      >
        <input
          ref={inputRef}
          type="file"
          className="sr-only"
          multiple={multiple}
          onChange={(e) => e.target.files && startUpload(e.target.files)}
        />
        <div className="flex flex-col items-center gap-3">
          <div className="flex h-12 w-12 items-center justify-center rounded-full bg-[#e5f9fc] text-[#0f172a] shadow-sm transition group-hover:bg-black group-hover:text-white">
            {items.some((it) => it.status === "uploading") ? (
              <Spinner />
            ) : (
              <Upload className="size-5" />
            )}
          </div>
          <p className="text-sm text-neutral-800">
            Arraste arquivos aqui ou <span className="font-semibold text-black underline decoration-dotted">selecione</span>
          </p>
          <p className="text-xs text-neutral-500">Máximo {Math.round(maxSize/1024/1024)}MB • Até {maxFiles} arquivos</p>
        </div>
      </div>
      {items.length > 0 && (
        <div className="space-y-2">
          {items.map((it) => (
            <div key={it.id} className="flex items-center justify-between gap-3 rounded-md border p-2 text-sm">
              <span className="truncate">{it.name}</span>
              <div className="flex min-w-[140px] items-center gap-2">
                <Progress value={it.progress} className="h-1.5 w-24" />
                <span className="w-10 text-right text-xs text-neutral-500">{it.progress}%</span>
              </div>
            </div>
          ))}
        </div>
      )}
    </div>
  )
}
