import { useCallback, useRef, useState } from "react";
import { Image, Loader2, Paperclip, X } from "lucide-react";
import { Button } from "@/components/ui/button";

type PendingFile = {
  id: string;
  name: string;
  size: number;
  preview?: string;
  uploading: boolean;
  progress: number;
};

type Props = {
  disabled?: boolean;
  onUploaded?: (url: string, filename: string) => void;
  maxFiles?: number;
  maxSize?: number;
};

export default function FileUploadButton({
  disabled,
  onUploaded,
  maxFiles = 5,
  maxSize = 50 * 1024 * 1024,
}: Props) {
  const [files, setFiles] = useState<PendingFile[]>([]);
  const [error, setError] = useState("");
  const inputRef = useRef<HTMLInputElement>(null);
  const idCounter = useRef(0);

  const handleFiles = useCallback(
    (selected: FileList | null) => {
      if (!selected || selected.length === 0) return;
      setError("");

      const newFiles: PendingFile[] = [];
      for (let i = 0; i < selected.length; i++) {
        const file = selected[i];
        if (file.size > maxSize) {
          setError(
            `${file.name} exceeds the ${(maxSize / 1024 / 1024).toFixed(0)} MB limit`,
          );
          continue;
        }
        if (files.length + newFiles.length >= maxFiles) {
          setError(`Maximum ${maxFiles} files allowed`);
          break;
        }
        const id = `upload-${++idCounter.current}`;
        const pending: PendingFile = {
          id,
          name: file.name,
          size: file.size,
          uploading: true,
          progress: 0,
          preview: file.type.startsWith("image/")
            ? URL.createObjectURL(file)
            : undefined,
        };
        newFiles.push(pending);
        simulateUpload(file)
          .then(() => {
            setFiles((prev) => prev.filter((f) => f.id !== id));
            onUploaded?.(`blob:${file.name}`, file.name);
          })
          .catch(() => {
            setFiles((prev) =>
              prev.map((f) =>
                f.id === id ? { ...f, uploading: false, progress: 0 } : f,
              ),
            );
            setError(`Failed to upload ${file.name}`);
          });
      }
      setFiles((prev) => [...prev, ...newFiles]);
      if (inputRef.current) inputRef.current.value = "";
    },
    [files.length, maxFiles, maxSize, onUploaded],
  );

  const removeFile = useCallback((id: string) => {
    setFiles((prev) => {
      const file = prev.find((f) => f.id === id);
      if (file?.preview) URL.revokeObjectURL(file.preview);
      return prev.filter((f) => f.id !== id);
    });
  }, []);

  const formatSize = (bytes: number) => {
    if (bytes < 1024) return `${bytes} B`;
    if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
    return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
  };

  return (
    <div className="relative">
      <input
        accept="image/*,.pdf,.doc,.docx,.txt,.zip"
        className="hidden"
        multiple
        onChange={(e) => handleFiles(e.target.files)}
        ref={inputRef}
        type="file"
      />

      <Button
        className="size-8 cursor-pointer rounded-lg text-muted-foreground/40 hover:bg-accent/50 hover:text-muted-foreground"
        disabled={disabled}
        onClick={() => inputRef.current?.click()}
        size="icon"
        title="Attach file"
        type="button"
        variant="ghost"
      >
        <Paperclip className="size-[15px]" />
      </Button>

      {files.length > 0 && (
        <div className="absolute bottom-full right-0 mb-2 w-72 space-y-1.5 rounded-xl border border-border/40 bg-card p-2.5 shadow-lg">
          {files.map((file) => (
            <div
              className="flex items-center gap-2.5 rounded-lg p-1.5 transition-colors hover:bg-accent/30"
              key={file.id}
            >
              {file.preview ? (
                <img
                  alt={file.name}
                  className="size-9 shrink-0 rounded-lg object-cover ring-1 ring-border/40"
                  src={file.preview}
                />
              ) : (
                <div className="grid size-9 shrink-0 place-items-center rounded-lg bg-muted/50">
                  <Image className="size-4 text-muted-foreground/40" />
                </div>
              )}
              <div className="min-w-0 flex-1">
                <p className="truncate text-[12px] font-medium text-foreground">
                  {file.name}
                </p>
                <p className="text-[11px] text-muted-foreground/50">
                  {formatSize(file.size)}
                  {file.uploading && (
                    <span className="ml-1.5 inline-flex items-center gap-1 text-primary/80">
                      <Loader2 className="size-2.5 animate-spin" />
                      uploading…
                    </span>
                  )}
                </p>
                {file.uploading && (
                  <div className="mt-1.5 h-[3px] overflow-hidden rounded-full bg-muted/50">
                    <div
                      className="h-full rounded-full bg-primary/60 transition-all duration-500"
                      style={{ width: `${Math.max(file.progress, 5)}%` }}
                    />
                  </div>
                )}
              </div>
              <Button
                aria-label="Remove file"
                className="size-8 shrink-0 cursor-pointer rounded-lg text-muted-foreground/40 hover:bg-accent/50 hover:text-foreground"
                onClick={() => removeFile(file.id)}
                size="icon"
                variant="ghost"
              >
                <X className="size-3" />
              </Button>
            </div>
          ))}
          {error && (
            <p className="rounded-md bg-destructive/[0.04] px-2.5 py-1.5 text-[11px] text-destructive/80">
              {error}
            </p>
          )}
        </div>
      )}
    </div>
  );
}

async function simulateUpload(_file: File): Promise<void> {
  return new Promise((resolve) => {
    setTimeout(resolve, 800 + Math.random() * 1200);
  });
}
