"use server";

/**
 * مدیریت عکس‌های محصول: آپلود، ترتیب، متن جایگزین، اتصال به تنوع (رنگ) و حذف.
 * فایل‌ها یکی‌یکی آپلود می‌شوند تا حجم هر درخواست کم بماند و پیشرفت قابل نمایش باشد.
 */
import { z } from "zod";
import { db } from "@/lib/db";
import { deleteStoredImage, ImageError, storeImage, storeProductImage } from "@/server/services/images";
import { refreshStorefront } from "./cache";
import { requireStaff } from "./guard";

const MAX_IMAGES_PER_PRODUCT = 12;
const productId = z.number().int().positive();
const imageId = z.string().min(1).max(40);

export interface AdminImage {
  id: string;
  url: string;
  alt: string;
  variantId: string | null;
}

async function listImages(pid: number): Promise<AdminImage[]> {
  return db.productImage.findMany({ where: { productId: pid }, orderBy: [{ sortOrder: "asc" }, { id: "asc" }], select: { id: true, url: true, alt: true, variantId: true } });
}

type Result = { ok: true; images: AdminImage[] } | { ok: false; error: string; images?: AdminImage[] };

export async function uploadProductImageAction(pid: number, formData: FormData): Promise<Result> {
  await requireStaff("products");
  if (!productId.safeParse(pid).success) return { ok: false, error: "محصول نامعتبر است" };
  const product = await db.product.findUnique({ where: { id: pid }, select: { name: true, _count: { select: { images: true } } } });
  if (!product) return { ok: false, error: "محصول پیدا نشد" };
  if (product._count.images >= MAX_IMAGES_PER_PRODUCT) return { ok: false, error: `حداکثر ${MAX_IMAGES_PER_PRODUCT} عکس برای هر محصول` };

  const file = formData.get("file");
  if (!(file instanceof File)) return { ok: false, error: "فایلی انتخاب نشده است" };

  try {
    const url = await storeProductImage(pid, file);
    const last = await db.productImage.aggregate({ where: { productId: pid }, _max: { sortOrder: true } });
    await db.productImage.create({ data: { productId: pid, url, alt: product.name, sortOrder: (last._max.sortOrder ?? -1) + 1 } });
  } catch (e) {
    if (e instanceof ImageError) return { ok: false, error: e.message };
    console.error("[images] آپلود ناموفق", e);
    return { ok: false, error: "ذخیره عکس ممکن نشد؛ دوباره تلاش کنید" };
  }
  refreshStorefront();
  return { ok: true, images: await listImages(pid) };
}

export async function deleteProductImageAction(id: string): Promise<Result> {
  await requireStaff("products");
  if (!imageId.safeParse(id).success) return { ok: false, error: "عکس نامعتبر است" };
  const image = await db.productImage.findUnique({ where: { id } });
  if (!image) return { ok: false, error: "عکس پیدا نشد" };
  await db.productImage.delete({ where: { id } });
  await deleteStoredImage(image.url);
  refreshStorefront();
  return { ok: true, images: await listImages(image.productId) };
}

/** ترتیب جدید: آرایه شناسه‌ها؛ اولین عکس، عکس اصلی محصول است */
export async function reorderProductImagesAction(pid: number, ids: string[]): Promise<Result> {
  await requireStaff("products");
  if (!productId.safeParse(pid).success || !z.array(imageId).max(MAX_IMAGES_PER_PRODUCT).safeParse(ids).success) return { ok: false, error: "درخواست نامعتبر است" };
  const current = await listImages(pid);
  if (ids.length !== current.length || !ids.every((id) => current.some((c) => c.id === id))) return { ok: false, error: "فهرست عکس‌ها تغییر کرده است؛ صفحه را تازه کنید", images: current };
  await db.$transaction(ids.map((id, i) => db.productImage.update({ where: { id }, data: { sortOrder: i } })));
  refreshStorefront();
  return { ok: true, images: await listImages(pid) };
}

const detailsSchema = z.object({
  alt: z.string().trim().min(2, "متن جایگزین حداقل ۲ کاراکتر").max(140).refine((s) => !/[<>]/.test(s), "کاراکتر غیرمجاز"),
  variantId: z.string().max(40).nullable(),
});

/** متن جایگزین (برای نابینایان و سئو) و تنوعی که عکس به آن تعلق دارد */
export async function updateProductImageAction(id: string, input: { alt: string; variantId: string | null }): Promise<Result> {
  await requireStaff("products");
  const parsed = detailsSchema.safeParse(input);
  if (!imageId.safeParse(id).success || !parsed.success) return { ok: false, error: parsed.error?.issues[0].message ?? "درخواست نامعتبر است" };
  const image = await db.productImage.findUnique({ where: { id }, select: { productId: true } });
  if (!image) return { ok: false, error: "عکس پیدا نشد" };
  const { variantId, alt } = parsed.data;
  if (variantId && !(await db.productVariant.findFirst({ where: { id: variantId, productId: image.productId } }))) return { ok: false, error: "تنوع انتخاب‌شده متعلق به این محصول نیست" };
  await db.productImage.update({ where: { id }, data: { alt, variantId } });
  refreshStorefront();
  return { ok: true, images: await listImages(image.productId) };
}

// ── عکس‌های تکی (بنر، کاور و متن مقاله) ─────────────────

const MEDIA_TARGETS = ["banners", "articles"] as const;

/** آپلود یک عکس برای بنر یا مجله؛ خروجی آدرس پایه WebP که در فرم مربوط ذخیره می‌شود */
export async function uploadMediaAction(target: (typeof MEDIA_TARGETS)[number], formData: FormData): Promise<{ ok: true; url: string } | { ok: false; error: string }> {
  await requireStaff(["banners", "magazine"]);
  if (!MEDIA_TARGETS.includes(target)) return { ok: false, error: "مقصد نامعتبر است" };
  const file = formData.get("file");
  if (!(file instanceof File)) return { ok: false, error: "فایلی انتخاب نشده است" };
  try {
    return { ok: true, url: await storeImage(target, file) };
  } catch (e) {
    if (e instanceof ImageError) return { ok: false, error: e.message };
    console.error("[images] آپلود ناموفق", e);
    return { ok: false, error: "ذخیره عکس ممکن نشد؛ دوباره تلاش کنید" };
  }
}
