import { FileImage, Upload } from "lucide-react";
import { type DragEvent, useCallback, useState } from "react";
import { cn } from "@/lib/utils";

const IMAGE_EXTENSIONS = new Set([
  "jpg",
  "jpeg",
  "png",
  "gif",
  "webp",
  "svg",
  "bmp",
  "avif",
  "tiff",
  "tif",
  "ico",
  "heic",
  "heif",
  "hif",
  "jxl",
  "apng",
  "dng",
  "cr2",
  "cr3",
  "nef",
  "nrw",
  "arw",
  "orf",
  "rw2",
  "raf",
  "pef",
  "3fr",
  "iiq",
  "srw",
  "x3f",
  "rwl",
  "gpr",
  "fff",
  "mrw",
  "mef",
  "kdc",
  "dcr",
  "erf",
  "ptx",
  "tga",
  "psd",
  "exr",
  "hdr",
  "svgz",
  "jp2",
  "j2k",
  "j2c",
  "jpc",
  "jpf",
  "jpx",
  "qoi",
  "eps",
  "epsf",
  "dds",
  "cur",
  "dpx",
  "cin",
  "fits",
  "fit",
  "fts",
  "pbm",
  "pgm",
  "ppm",
  "pnm",
  "pam",
  "pfm",
]);

export function isImageFile(file: File): boolean {
  if (file.type.startsWith("image/")) return true;
  const ext = file.name.split(".").pop()?.toLowerCase() ?? "";
  return IMAGE_EXTENSIONS.has(ext);
}

interface DropzoneProps {
  onFiles?: (files: File[]) => void;
  accept?: string;
  multiple?: boolean;
  /** Files that have already been dropped (for showing count & list). */
  currentFiles?: File[];
  /** Use a smaller layout that fits constrained containers like the pipeline preview. */
  compact?: boolean;
}

// Browsers may not map certain formats (HEIC, JXL, RAW, etc.) to image/* in file pickers.
// Append explicit extensions so they are selectable.
function expandAccept(accept?: string): string | undefined {
  if (!accept?.includes("image/*")) return accept;
  return `${accept},.avif,.heic,.heif,.hif,.jxl,.ico,.dng,.cr2,.cr3,.nef,.nrw,.arw,.orf,.rw2,.raf,.pef,.3fr,.iiq,.srw,.x3f,.rwl,.gpr,.fff,.mrw,.mef,.kdc,.dcr,.erf,.ptx,.tga,.psd,.exr,.hdr,.svgz,.jp2,.j2k,.j2c,.jpc,.jpf,.jpx,.qoi,.eps,.epsf,.dds,.cur,.apng,.dpx,.cin,.fits,.fit,.fts,.ppm,.pgm,.pbm,.pnm,.pam,.pfm`;
}

export function Dropzone({
  onFiles,
  accept,
  multiple = true,
  currentFiles = [],
  compact = false,
}: DropzoneProps) {
  const resolvedAccept = expandAccept(accept);
  const [isDragging, setIsDragging] = useState(false);

  const handleDrag = useCallback((e: DragEvent) => {
    e.preventDefault();
    e.stopPropagation();
    if (e.type === "dragenter" || e.type === "dragover") setIsDragging(true);
    else if (e.type === "dragleave") setIsDragging(false);
  }, []);

  const handleDrop = useCallback(
    (e: DragEvent) => {
      e.preventDefault();
      e.stopPropagation();
      setIsDragging(false);
      const files = Array.from(e.dataTransfer.files).filter(isImageFile);
      if (files.length > 0) onFiles?.(files);
    },
    [onFiles],
  );

  const handleClick = () => {
    const input = document.createElement("input");
    input.type = "file";
    input.multiple = multiple;
    if (resolvedAccept) input.accept = resolvedAccept;
    input.onchange = (e) => {
      const files = Array.from((e.target as HTMLInputElement).files || []);
      if (files.length > 0) onFiles?.(files);
    };
    input.click();
  };

  const hasMultipleFiles = currentFiles.length > 1;

  return (
    <section
      aria-label="File drop zone"
      onDragEnter={handleDrag}
      onDragOver={handleDrag}
      onDragLeave={handleDrag}
      onDrop={handleDrop}
      className={cn(
        "flex flex-col items-center justify-center rounded-2xl border-2 border-dashed transition-colors mx-auto max-w-2xl w-full",
        compact ? "min-h-0 h-full" : "min-h-[400px]",
        isDragging
          ? "border-primary bg-primary/5"
          : "border-border bg-muted/30 hover:border-primary/50 hover:bg-muted/50",
      )}
    >
      <div className={cn("flex flex-col items-center", compact ? "gap-2 p-4" : "gap-4 p-8")}>
        <div className="text-3xl font-bold text-muted-foreground/30">
          <span className="text-primary/30">SnapOtter</span>
        </div>
        <button
          type="button"
          onClick={handleClick}
          className="flex items-center gap-2 px-6 py-2.5 rounded-lg border border-primary text-primary hover:bg-primary/5 transition-colors text-sm font-medium"
        >
          <Upload className="h-4 w-4" />
          Upload from computer
        </button>
        <p className="text-sm text-muted-foreground">Drop files here or click the upload button</p>

        {/* Show file count badge and list when multiple files are dropped */}
        {hasMultipleFiles && (
          <div className="flex flex-col items-center gap-2 mt-2">
            <span className="inline-flex items-center gap-1.5 px-3 py-1 rounded-full bg-primary/10 text-primary text-xs font-medium">
              <FileImage className="h-3.5 w-3.5" />
              {currentFiles.length} files selected
            </span>
            <div className="max-h-32 overflow-y-auto w-full max-w-xs">
              {currentFiles.map((f) => (
                <div
                  key={f.name}
                  className="flex items-center justify-between text-xs text-muted-foreground px-2 py-0.5"
                >
                  <span className="truncate">{f.name}</span>
                  <span className="shrink-0 ml-2">{(f.size / 1024).toFixed(0)} KB</span>
                </div>
              ))}
            </div>
          </div>
        )}
      </div>
    </section>
  );
}
