"use client";

/**
 * مدیریت عکس‌های محصول در پنل: آپلود چندتایی (یکی‌یکی با نمایش پیشرفت)، جابه‌جایی ترتیب،
 * متن جایگزین، اتصال عکس به یک رنگ/تنوع و حذف. هر تغییر بلافاصله در سرور ذخیره می‌شود.
 */
import { useRef, useState, useTransition } from "react";
import { Icon } from "@/components/ui/Icon";
import { faNumber } from "@/lib/format";
import { imageSrc } from "@/lib/media";
import {
  deleteProductImageAction,
  reorderProductImagesAction,
  updateProductImageAction,
  uploadProductImageAction,
  type AdminImage,
} from "@/server/admin/images";

interface Props {
  productId: number;
  initial: AdminImage[];
  variants: { id: string; label: string }[];
  onChange?: (images: AdminImage[]) => void;
}

const ACCEPT = "image/*,.heic,.heif";
const MAX_BYTES = 10 * 1024 * 1024;

export function ProductImageManager({ productId, initial, variants, onChange }: Props) {
  const [images, setImagesState] = useState(initial);
  const [error, setError] = useState("");
  const [progress, setProgress] = useState<{ done: number; total: number } | null>(null);
  const [dragOver, setDragOver] = useState(false);
  const [pending, start] = useTransition();
  const inputRef = useRef<HTMLInputElement>(null);

  const setImages = (next: AdminImage[]) => {
    setImagesState(next);
    onChange?.(next);
  };

  async function upload(files: File[]) {
    setError("");
    const errors: string[] = [];
    setProgress({ done: 0, total: files.length });
    for (const [i, file] of files.entries()) {
      // بررسی اولیه در مرورگر؛ بررسی اصلی در سرور انجام می‌شود
      if (file.size > MAX_BYTES) {
        errors.push(`${file.name}: حجم بیش از ۱۰ مگابایت`);
      } else {
        const fd = new FormData();
        fd.set("file", file);
        const res = await uploadProductImageAction(productId, fd).catch(() => ({ ok: false as const, error: "ارتباط با سرور قطع شد" }));
        if (res.ok) setImages(res.images);
        else errors.push(`${file.name}: ${res.error}`);
      }
      setProgress({ done: i + 1, total: files.length });
    }
    setProgress(null);
    setError(errors.join("\n"));
    if (inputRef.current) inputRef.current.value = "";
  }

  function run(action: () => Promise<{ ok: boolean; error?: string; images?: AdminImage[] }>) {
    setError("");
    start(async () => {
      const res = await action();
      if (res.images) setImages(res.images);
      if (!res.ok) setError(res.error ?? "خطا");
    });
  }

  function move(index: number, delta: number) {
    const next = [...images];
    const [item] = next.splice(index, 1);
    next.splice(index + delta, 0, item);
    setImages(next); // نمایش فوری
    run(() => reorderProductImagesAction(productId, next.map((i) => i.id)));
  }

  const busy = pending || progress !== null;

  return (
    <div className="space-y-3">
      <div
        onDragOver={(e) => {
          e.preventDefault();
          setDragOver(true);
        }}
        onDragLeave={() => setDragOver(false)}
        onDrop={(e) => {
          e.preventDefault();
          setDragOver(false);
          const files = Array.from(e.dataTransfer.files).filter((f) => f.type.startsWith("image/"));
          if (files.length && !busy) void upload(files);
        }}
        className={`rounded-xl border border-dashed p-4 text-center transition ${dragOver ? "border-ink bg-mist" : "border-line"}`}
      >
        <Icon name="plus" size={18} className="mx-auto" />
        <p className="mt-2 text-xs leading-5 text-muted">عکس‌ها را این‌جا رها کنید یا</p>
        <button type="button" className="btn-outline mt-2 h-9 px-4 text-xs" disabled={busy} onClick={() => inputRef.current?.click()}>
          انتخاب عکس
        </button>
        <input
          ref={inputRef}
          type="file"
          accept={ACCEPT}
          multiple
          className="sr-only"
          tabIndex={-1}
          onChange={(e) => e.target.files?.length && void upload(Array.from(e.target.files))}
        />
        <p className="mt-2 text-[11px] leading-5 text-muted">هر فرمت و هر ابعادی (JPG، PNG، HEIC، GIF…) خودکار به WebP مربع ۱:۱ تبدیل می‌شود: عکس بدون کشیدگی وسط کادر و اطرافش خاکستری یکدست · حداکثر ۱۰ مگابایت</p>
      </div>

      {progress && (
        <div role="status" className="text-xs">
          در حال آپلود {faNumber(progress.done + 1 > progress.total ? progress.total : progress.done + 1)} از {faNumber(progress.total)}…
          <div className="mt-1 h-1 overflow-hidden rounded-full bg-mist">
            <div className="h-full bg-ink transition-all" style={{ width: `${(progress.done / progress.total) * 100}%` }} />
          </div>
        </div>
      )}
      {error && (
        <p role="alert" className="whitespace-pre-line rounded-lg bg-mist px-3 py-2 text-xs leading-5">
          ⚠ {error}
        </p>
      )}

      {images.length > 0 && (
        <ul className="space-y-3">
          {images.map((img, i) => (
            <li key={img.id} className="flex gap-3 rounded-xl border border-line p-2">
              <div className="relative size-20 shrink-0 overflow-hidden rounded-lg bg-mist">
                {/* eslint-disable-next-line @next/next/no-img-element */}
                <img src={imageSrc(img.url, 400)} alt={img.alt} className="size-full object-cover" />
                {i === 0 && <span className="absolute inset-x-0 bottom-0 bg-ink/80 py-0.5 text-center text-[10px] text-paper">عکس اصلی</span>}
              </div>
              <div className="min-w-0 flex-1 space-y-1.5">
                <input
                  className="field h-8 text-xs"
                  defaultValue={img.alt}
                  aria-label="متن جایگزین عکس"
                  placeholder="متن جایگزین (توضیح عکس)"
                  maxLength={140}
                  onBlur={(e) => e.target.value.trim() !== img.alt && run(() => updateProductImageAction(img.id, { alt: e.target.value, variantId: img.variantId }))}
                />
                {variants.length > 1 && (
                  <select
                    className="field h-8 text-xs"
                    value={img.variantId ?? ""}
                    aria-label="تنوع مربوط به عکس"
                    onChange={(e) => run(() => updateProductImageAction(img.id, { alt: img.alt, variantId: e.target.value || null }))}
                  >
                    <option value="">همه تنوع‌ها</option>
                    {variants.map((v) => (
                      <option key={v.id} value={v.id}>{v.label}</option>
                    ))}
                  </select>
                )}
                <div className="flex items-center gap-1">
                  <button type="button" className="grid size-7 place-items-center rounded-full hover:bg-mist disabled:opacity-30" disabled={busy || i === 0} onClick={() => move(i, -1)} aria-label="انتقال به قبل">
                    <Icon name="chevron-right" size={14} />
                  </button>
                  <button type="button" className="grid size-7 place-items-center rounded-full hover:bg-mist disabled:opacity-30" disabled={busy || i === images.length - 1} onClick={() => move(i, 1)} aria-label="انتقال به بعد">
                    <Icon name="chevron-left" size={14} />
                  </button>
                  <button
                    type="button"
                    className="ms-auto grid size-7 place-items-center rounded-full hover:bg-mist"
                    disabled={busy}
                    aria-label="حذف عکس"
                    onClick={() => confirm("این عکس حذف شود؟") && run(() => deleteProductImageAction(img.id))}
                  >
                    <Icon name="trash" size={14} />
                  </button>
                </div>
              </div>
            </li>
          ))}
        </ul>
      )}
    </div>
  );
}
