import { useState, useRef, useCallback } from "react";
import { UploadCloud, FilePlus, FolderOpen } from "lucide-react";

import { Button } from "@/components/ui/Button";
import { ACCEPTED_INVOICE_MIME_TYPES, MAX_INVOICE_FILE_SIZE_BYTES } from "@rubis/shared";
import { cn } from "@/lib/utils";

/**
 * Dropzone — zone de drag & drop multi-fichiers pour les factures.
 *
 * Cf. wireframe 2.1 et CLAUDE.md (principe "3 clics maximum"). C'est le geste
 * principal d'import — le clic "parcourir" est le fallback discret.
 *
 * En V1, la primitive ne fait que recevoir les File[] et les passer à
 * `onFiles`. L'upload, l'OCR et la création des invoices se passent en aval
 * (backend Adonis ou MSW).
 */
type DropzoneProps = {
  /** Variant pleine page (empty state) vs compact (dans un coin). */
  variant?: "full" | "compact";
  /** Max files acceptés en un drop. Default 20 (cf. wireframe). */
  maxFiles?: number;
  /** Callback quand des fichiers valides ont été sélectionnés. */
  onFiles?: (files: File[]) => void;
  /** Mode chargement : disable input + remplace le call to action par un spinner. */
  isUploading?: boolean;
  className?: string;
};

const ACCEPT_ATTR = ACCEPTED_INVOICE_MIME_TYPES.join(",");

/**
 * Vérification souple : on accepte par MIME OU par extension. Certains
 * navigateurs (ou drag depuis Finder/Explorer) renvoient un `type` vide,
 * il ne faut pas rejeter pour autant. La taille trop grande renvoie un
 * message dédié, pas le générique "format non supporté".
 */
type FileCheckResult = { ok: true } | { ok: false; reason: "format" | "size" };

function checkFile(file: File): FileCheckResult {
  const acceptableMime =
    file.type === "" ||
    (ACCEPTED_INVOICE_MIME_TYPES as readonly string[]).includes(file.type);
  const acceptableExt = /\.(pdf|png|jpe?g)$/iu.test(file.name);
  if (!acceptableMime && !acceptableExt) return { ok: false, reason: "format" };
  if (file.size > MAX_INVOICE_FILE_SIZE_BYTES) return { ok: false, reason: "size" };
  return { ok: true };
}

export function Dropzone({
  variant = "full",
  maxFiles = 20,
  onFiles,
  isUploading = false,
  className,
}: DropzoneProps) {
  const [isDragging, setIsDragging] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const inputRef = useRef<HTMLInputElement>(null);

  const handleFiles = useCallback(
    (fileList: FileList | null) => {
      if (!fileList || isUploading) return;
      const files = Array.from(fileList);
      if (files.length === 0) return;
      if (files.length > maxFiles) {
        setError(`Maximum ${maxFiles} fichiers en un seul drop.`);
        return;
      }
      const checks = files.map((f) => ({ file: f, ...checkFile(f) }));
      const valid = checks.filter((c) => c.ok).map((c) => c.file);
      const tooBig = checks.filter((c) => !c.ok && c.reason === "size").length;
      const wrongFormat = checks.filter(
        (c) => !c.ok && c.reason === "format",
      ).length;

      if (valid.length === 0) {
        if (tooBig > 0) {
          setError(`Fichier trop lourd · 10 Mo maximum par fichier.`);
        } else if (wrongFormat > 0) {
          setError("Format non supporté. PDF, PNG, JPG uniquement.");
        }
        return;
      }
      setError(null);
      onFiles?.(valid);
    },
    [maxFiles, onFiles, isUploading],
  );

  const onDragOver = (e: React.DragEvent) => {
    e.preventDefault();
    setIsDragging(true);
  };
  const onDragLeave = (e: React.DragEvent) => {
    e.preventDefault();
    setIsDragging(false);
  };
  const onDrop = (e: React.DragEvent) => {
    e.preventDefault();
    setIsDragging(false);
    handleFiles(e.dataTransfer.files);
  };

  const isFull = variant === "full";

  return (
    <div
      onDragOver={onDragOver}
      onDragLeave={onDragLeave}
      onDrop={onDrop}
      className={cn(
        "rounded-card border-2 border-dashed bg-cream-2/40 transition-colors duration-150",
        "flex flex-col items-center justify-center text-center",
        isFull ? "py-16 px-8 min-h-[360px]" : "py-8 px-6 min-h-[160px]",
        isDragging
          ? "border-rubis bg-rubis-glow/30"
          : "border-line hover:border-ink-3",
        className,
      )}
    >
      <div
        className={cn(
          "flex size-14 items-center justify-center rounded-full bg-white",
          "border border-line shadow-soft",
          isDragging && "border-rubis text-rubis",
        )}
      >
        <UploadCloud
          size={26}
          strokeWidth={1.75}
          className={isDragging ? "text-rubis" : "text-ink-2"}
          aria-hidden="true"
        />
      </div>

      <p
        className={cn(
          "mt-5 font-display tracking-[-0.018em] text-ink",
          isFull ? "text-[22px] font-semibold" : "text-[17px] font-semibold",
        )}
      >
        {isUploading ? (
          <>
            On <em className="text-rubis">lit</em> vos factures…
          </>
        ) : isDragging ? (
          <>
            Lâchez ici, on s&apos;<em className="text-rubis">occupe</em> du reste.
          </>
        ) : (
          <>
            Glissez vos factures <em className="text-rubis">ici</em>.
          </>
        )}
      </p>
      <p className="mt-2 text-[13px] text-ink-2">
        PDF, PNG, JPG · jusqu&apos;à {maxFiles} fichiers en simultané · 10 Mo par fichier
      </p>

      <div className="mt-6 flex flex-col items-center gap-3 sm:flex-row">
        <Button
          variant="secondary"
          size="sm"
          onClick={() => inputRef.current?.click()}
          type="button"
          loading={isUploading}
          disabled={isUploading}
        >
          <FolderOpen size={14} aria-hidden="true" /> Parcourir mes fichiers
        </Button>
        {isFull && !isUploading && (
          <Button variant="ghost" size="sm" type="button">
            <FilePlus size={14} aria-hidden="true" /> Saisir manuellement
          </Button>
        )}
      </div>

      {error && (
        <p className="mt-4 text-[13px] font-medium text-rubis-deep" role="alert">
          {error}
        </p>
      )}

      <input
        ref={inputRef}
        type="file"
        accept={ACCEPT_ATTR}
        multiple
        className="sr-only"
        onChange={(e) => handleFiles(e.target.files)}
      />

      {isFull && (
        <p className="mt-8 text-[12px] text-ink-3 max-w-md">
          L&apos;OCR fait le reste — vérifiez en 30 secondes et lancez la relance.
        </p>
      )}
    </div>
  );
}
