import React, { useCallback, useState } from "react";

interface DropzoneProps {
  accept?: string;
  multiple?: boolean;
  maxFiles?: number;
  maxSizeMb?: number;
  onFilesDrop: (files: File[]) => void;
  className?: string;
}

function matchesAccept(file: File, accept?: string): boolean {
  if (!accept) return true;
  const rules = accept.split(",").map((rule) => rule.trim()).filter(Boolean);
  if (rules.length === 0) return true;

  return rules.some((rule) => {
    if (rule.endsWith("/*")) return file.type.startsWith(rule.slice(0, -1));
    if (rule.startsWith(".")) return file.name.toLowerCase().endsWith(rule.toLowerCase());
    return file.type === rule;
  });
}

export function Dropzone({
  accept,
  multiple = false,
  maxFiles,
  maxSizeMb,
  onFilesDrop,
  className = "",
}: DropzoneProps) {
  const [isDragActive, setIsDragActive] = useState(false);
  const [error, setError] = useState<string | null>(null);

  const normalizeFiles = useCallback((incomingFiles: File[]) => {
    const pickedFiles = multiple ? incomingFiles : incomingFiles.slice(0, 1);
    const limitedFiles = maxFiles ? pickedFiles.slice(0, maxFiles) : pickedFiles;
    const maxBytes = maxSizeMb ? maxSizeMb * 1024 * 1024 : undefined;

    const invalidType = limitedFiles.find((file) => !matchesAccept(file, accept));
    if (invalidType) {
      setError(`${invalidType.name} is not an accepted file type.`);
      return null;
    }

    const oversized = maxBytes
      ? limitedFiles.find((file) => file.size > maxBytes)
      : undefined;
    if (oversized) {
      setError(`${oversized.name} is larger than ${maxSizeMb} MB.`);
      return null;
    }

    setError(null);
    return limitedFiles;
  }, [accept, maxFiles, maxSizeMb, multiple]);

  const handleDragEnter = useCallback((e: React.DragEvent) => {
    e.preventDefault();
    e.stopPropagation();
    setIsDragActive(true);
  }, []);

  const handleDragLeave = useCallback((e: React.DragEvent) => {
    e.preventDefault();
    e.stopPropagation();
    setIsDragActive(false);
  }, []);

  const handleDragOver = useCallback((e: React.DragEvent) => {
    e.preventDefault();
    e.stopPropagation();
    if (!isDragActive) {
      setIsDragActive(true);
    }
  }, [isDragActive]);

  const handleDrop = useCallback(
    (e: React.DragEvent) => {
      e.preventDefault();
      e.stopPropagation();
      setIsDragActive(false);

      if (e.dataTransfer.files && e.dataTransfer.files.length > 0) {
        const droppedFiles = normalizeFiles(Array.from(e.dataTransfer.files));
        if (droppedFiles) onFilesDrop(droppedFiles);
        e.dataTransfer.clearData();
      }
    },
    [normalizeFiles, onFilesDrop]
  );

  const handleChange = useCallback(
    (e: React.ChangeEvent<HTMLInputElement>) => {
      e.preventDefault();
      if (e.target.files && e.target.files.length > 0) {
        const selectedFiles = normalizeFiles(Array.from(e.target.files));
        if (selectedFiles) onFilesDrop(selectedFiles);
      }
    },
    [normalizeFiles, onFilesDrop]
  );

  return (
    <div
      className={`relative flex flex-col items-center justify-center p-6 border-2 border-dashed rounded-[14px] min-h-[140px] transition-colors cursor-pointer text-center ${
        isDragActive
          ? "border-[var(--p-accent)] bg-opacity-10 bg-[var(--p-accent)]"
          : "border-[var(--p-border)] hover:bg-[var(--p-surface)]"
      } ${className}`}
      onDragEnter={handleDragEnter}
      onDragLeave={handleDragLeave}
      onDragOver={handleDragOver}
      onDrop={handleDrop}
    >
      <input
        type="file"
        accept={accept}
        multiple={multiple}
        onChange={handleChange}
        className="absolute inset-0 w-full h-full opacity-0 cursor-pointer"
      />
      <div className="flex flex-col items-center gap-2 pointer-events-none">
        <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="var(--p-muted)" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
          <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" />
          <polyline points="17 8 12 3 7 8" />
          <line x1="12" y1="3" x2="12" y2="15" />
        </svg>
        <span className="font-sans text-[13px] font-medium text-[var(--p-text)]">
          {isDragActive ? "Drop files now" : "Drop files here or click to browse"}
        </span>
        {error && (
          <span className="font-sans text-[12px] text-red-600">
            {error}
          </span>
        )}
      </div>
    </div>
  );
}
