"use client";

import * as React from "react";
import { ImagePlus, Loader2, Trash2 } from "lucide-react";
import { cn } from "@/lib/utils";
import { deleteUpload, uploadImages } from "@/lib/actions/uploads";
import {
  IMAGE_ACCEPT,
  IMAGE_EXT_BY_MIME,
  UPLOAD_MAX_BYTES,
  formatBytes,
} from "@/lib/upload-config";

interface ImageUploadInputProps {
  /** Currently stored public path (e.g. "/upload/products/abc.webp"), if any. */
  value?: string | null;
  /** Called with the new public path after upload, or null when cleared. */
  onChange: (value: string | null) => void;
  /** Upload sub-folder under /upload/ (must be whitelisted server-side). */
  folder?: string;
  label?: string;
  className?: string;
  disabled?: boolean;
}

/**
 * File-upload input backed by the shared upload server action. Shows the
 * current image with Replace/Remove actions, or a click-to-upload drop zone
 * when empty. Uploads happen on selection — the produced /upload/... path is
 * what the parent form stores and later saves.
 *
 * Cleanup: a file uploaded in *this session* and then replaced/removed is
 * deleted immediately (it cannot be referenced anywhere yet). Pre-existing
 * images are left to the server, which prunes them on save when no longer used.
 */
export function ImageUploadInput({
  value,
  onChange,
  folder = "products",
  label,
  className,
  disabled,
}: ImageUploadInputProps) {
  const inputRef = React.useRef<HTMLInputElement>(null);
  const [uploading, setUploading] = React.useState(false);
  const [message, setMessage] = React.useState<{ ok: boolean; text: string } | null>(null);
  const [dragging, setDragging] = React.useState(false);
  const sessionUploaded = React.useRef(new Set<string>());

  const accept = `${IMAGE_ACCEPT}`;
  const busy = uploading || disabled;

  async function handleUpload(file?: File) {
    if (!file) return;
    if (!(file.type in IMAGE_EXT_BY_MIME)) {
      setMessage({ ok: false, text: "Only JPG, PNG, WebP or GIF images are supported." });
      return;
    }
    if (file.size > UPLOAD_MAX_BYTES) {
      setMessage({ ok: false, text: `That image is too large — max ${formatBytes(UPLOAD_MAX_BYTES)}.` });
      return;
    }
    setUploading(true);
    setMessage(null);
    const formData = new FormData();
    formData.append("file", file);
    const result = await uploadImages(formData, folder);
    if (inputRef.current) inputRef.current.value = "";
    setUploading(false);
    if (!result.ok) {
      setMessage({ ok: false, text: result.error });
      return;
    }
    const nextPath = result.data?.paths?.[0];
    if (!nextPath) {
      setMessage({ ok: false, text: "Upload returned no file." });
      return;
    }

    // A previous value chosen in this session can go now — it can't be
    // referenced anywhere yet. Existing saved images are pruned on save.
    const previous = value;
    if (previous && sessionUploaded.current.has(previous)) {
      await deleteUpload(previous).catch(() => {});
      sessionUploaded.current.delete(previous);
    }
    sessionUploaded.current.add(nextPath);
    onChange(nextPath);
    setMessage({ ok: true, text: "Image uploaded." });
  }

  async function handleRemove() {
    if (!value) return;
    if (sessionUploaded.current.has(value)) {
      await deleteUpload(value).catch(() => {});
      sessionUploaded.current.delete(value);
    }
    if (inputRef.current) inputRef.current.value = "";
    onChange(null);
    setMessage(null);
  }

  return (
    <div className={cn("space-y-2", className)}>
      <input
        ref={inputRef}
        type="file"
        accept={accept}
        className="sr-only"
        onChange={(e) => handleUpload(e.target.files?.[0])}
        disabled={busy}
      />

      {value ? (
        <div className="flex flex-col gap-3 sm:flex-row sm:items-center">
          <div className="relative aspect-square w-32 shrink-0 overflow-hidden rounded-xl border border-border bg-muted">
            {/* eslint-disable-next-line @next/next/no-img-element */}
            <img
              src={value}
              alt={label ?? "Uploaded image"}
              className="h-full w-full object-cover"
            />
          </div>
          <div className="space-y-2">
            <div className="flex flex-wrap items-center gap-2">
              <button
                type="button"
                onClick={() => inputRef.current?.click()}
                disabled={busy}
                className="inline-flex h-9 cursor-pointer items-center gap-1.5 rounded-full border border-input bg-background px-4 text-sm font-medium text-foreground shadow-xs transition-colors hover:bg-accent focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:opacity-60"
              >
                {uploading ? (
                  <Loader2 className="h-4 w-4 animate-spin" />
                ) : (
                  <ImagePlus className="h-4 w-4" />
                )}
                {uploading ? "Uploading…" : "Replace"}
              </button>
              <button
                type="button"
                onClick={handleRemove}
                disabled={busy}
                className="inline-flex h-9 items-center gap-1.5 rounded-full border border-input bg-background px-4 text-sm font-medium text-destructive shadow-xs transition-colors hover:bg-destructive/10 disabled:opacity-60"
              >
                <Trash2 className="h-4 w-4" />
                Remove
              </button>
            </div>
            <button
              type="button"
              onClick={() => inputRef.current?.click()}
              disabled={busy}
              className="block max-w-full truncate text-xs text-muted-foreground underline-offset-2 hover:underline"
            >
              {value}
            </button>
          </div>
        </div>
      ) : (
        <button
          type="button"
          onClick={() => inputRef.current?.click()}
          onDragOver={(e) => {
            e.preventDefault();
            setDragging(true);
          }}
          onDragLeave={() => setDragging(false)}
          onDrop={(e) => {
            e.preventDefault();
            setDragging(false);
            handleUpload(e.dataTransfer.files?.[0]);
          }}
          disabled={busy}
          className={cn(
            "flex w-full max-w-md flex-col items-center justify-center gap-2 rounded-xl border-2 border-dashed px-6 py-8 text-center transition-colors",
            dragging
              ? "border-primary bg-primary/5"
              : "border-border bg-muted/40 hover:border-primary hover:bg-primary/5",
            busy && "pointer-events-none opacity-60",
          )}
        >
          {uploading ? (
            <Loader2 className="h-6 w-6 animate-spin text-muted-foreground" />
          ) : (
            <ImagePlus className="h-6 w-6 text-muted-foreground" />
          )}
          <span className="text-sm font-medium text-foreground">
            {uploading ? "Uploading…" : "Click to upload or drag & drop"}
          </span>
          <span className="text-xs text-muted-foreground">
            JPG, PNG, WebP or GIF up to {formatBytes(UPLOAD_MAX_BYTES)}
          </span>
        </button>
      )}

      {message && (
        <p
          className={cn(
            "text-xs",
            message.ok ? "text-green-600" : "text-destructive",
          )}
          role={message.ok ? undefined : "alert"}
        >
          {message.text}
        </p>
      )}
    </div>
  );
}