"use server";

/** دسته‌ها، برندها و بنرهای صفحه اصلی */
import { revalidatePath } from "next/cache";
import { redirect } from "next/navigation";
import { z } from "zod";
import { db } from "@/lib/db";
import { slugifyFa } from "@/lib/persian";
import { rebuildSearchText } from "@/server/services/search-index";
import { deleteStoredImage } from "@/server/services/images";
import { storage } from "@/integrations/storage";
import { refreshStorefront } from "./cache";
import { requireStaff } from "./guard";

const txt = (min: number, max: number) => z.string().trim().min(min).max(max).refine((s) => !/[<>]/.test(s), "کاراکتر غیرمجاز");
const optTxt = (max: number) => z.preprocess((v) => (v === "" || v == null ? undefined : v), txt(1, max).optional());
const back = (path: string, error?: string) => redirect(error ? `${path}?error=${encodeURIComponent(error)}` : `${path}?saved=1`);

// ── دسته‌ها ───────────────────────────────────────────

const categorySchema = z.object({
  id: optTxt(40),
  name: txt(2, 60),
  slug: optTxt(80),
  parentId: optTxt(40),
  description: optTxt(300),
  sortOrder: z.coerce.number().int().min(0).max(999).default(0),
  isActive: z.preprocess((v) => v === "on", z.boolean()),
});

export async function saveCategoryAction(formData: FormData) {
  await requireStaff("catalog");
  const parsed = categorySchema.safeParse(Object.fromEntries(formData));
  if (!parsed.success) return back("/admin/catalog", "اطلاعات دسته معتبر نیست");
  const { id, slug, parentId, ...rest } = parsed.data;
  if (id && parentId === id) return back("/admin/catalog", "دسته نمی‌تواند والد خودش باشد");
  // فقط دو سطح: والد باید خودش دسته اصلی باشد
  if (parentId) {
    const parent = await db.category.findUnique({ where: { id: parentId }, select: { parentId: true } });
    if (!parent || parent.parentId) return back("/admin/catalog", "والد باید یک دسته اصلی باشد");
  }
  const data = { ...rest, slug: slugifyFa(slug || rest.name), parentId: parentId ?? null };
  const clash = await db.category.findFirst({ where: { slug: data.slug, ...(id ? { id: { not: id } } : {}) } });
  if (clash) return back("/admin/catalog", "این اسلاگ برای دسته دیگری استفاده شده است");
  if (id) {
    await db.category.update({ where: { id }, data });
    // نام دسته (و دسته والد) در متن جستجوی محصولات استفاده شده است
    await rebuildSearchText({ OR: [{ categoryId: id }, { category: { parentId: id } }] });
  } else await db.category.create({ data });
  refreshStorefront({ categories: true });
  revalidatePath("/admin/catalog");
  back("/admin/catalog");
}

// ── برندها ───────────────────────────────────────────

const brandSchema = z.object({
  id: optTxt(40),
  name: txt(2, 60),
  nameEn: z.string().trim().min(2).max(60).regex(/^[A-Za-z0-9 &.'-]+$/, "نام لاتین معتبر نیست"),
  slug: optTxt(60),
  country: txt(2, 40),
  description: txt(5, 400),
  isActive: z.preprocess((v) => v === "on", z.boolean()),
});

export async function saveBrandAction(formData: FormData) {
  await requireStaff("catalog");
  const parsed = brandSchema.safeParse(Object.fromEntries(formData));
  if (!parsed.success) return back("/admin/catalog", parsed.error.issues[0].message);
  const { id, slug, ...rest } = parsed.data;
  const data = { ...rest, nameEn: rest.nameEn.toUpperCase(), slug: slugifyFa(slug || rest.nameEn) };
  const clash = await db.brand.findFirst({ where: { slug: data.slug, ...(id ? { id: { not: id } } : {}) } });
  if (clash) return back("/admin/catalog", "این اسلاگ برای برند دیگری استفاده شده است");
  if (id) {
    await db.brand.update({ where: { id }, data });
    // نام برند در متن جستجوی محصولاتش هم استفاده شده است
    await rebuildSearchText({ brandId: id });
  } else await db.brand.create({ data });
  refreshStorefront();
  revalidatePath("/admin/catalog");
  back("/admin/catalog");
}

// ── بنرها ────────────────────────────────────────────

const SHAPES = ["dropper", "bottle", "pump", "tube", "jar", "lipstick", "wand", "compact", "palette", "perfume"] as const;

export async function saveBannerAction(formData: FormData) {
  await requireStaff("banners");
  const parsed = z
    .object({
      id: optTxt(40),
      eyebrow: txt(1, 40),
      title: txt(2, 80),
      subtitle: txt(2, 200),
      cta: txt(2, 30),
      // فقط لینک داخلی سایت مجاز است
      href: z.string().trim().max(200).regex(/^\/(?!\/)[^\s<>]*$/, "لینک باید آدرس داخلی سایت باشد (با / شروع شود)"),
      theme: z.enum(["dark", "light", "mist"]),
      sortOrder: z.coerce.number().int().min(0).max(99).default(0),
      isActive: z.preprocess((v) => v === "on", z.boolean()),
    })
    .safeParse(Object.fromEntries(formData));
  if (!parsed.success) return back("/admin/banners", parsed.error.issues[0].message);

  // ترکیب تصویری: تا ۳ ظرف با شکل و رنگ
  const art = [0, 1, 2].flatMap((i) => {
    const shape = String(formData.get(`shape${i}`) ?? "");
    const tone = String(formData.get(`tone${i}`) ?? "");
    return SHAPES.includes(shape as (typeof SHAPES)[number]) && /^#[0-9a-f]{6}$/i.test(tone) ? [{ shape, tone }] : [];
  });
  // عکس بنر: فقط آدرسی که در فضای ذخیره خود سایت آپلود شده پذیرفته می‌شود
  const imageUrl = String(formData.get("imageUrl") ?? "").trim() || null;
  if (imageUrl && !storage().keyFromUrl(imageUrl)) return back("/admin/banners", "آدرس عکس نامعتبر است");
  const imageAlt = String(formData.get("imageAlt") ?? "").trim().slice(0, 140).replace(/[<>]/g, "") || null;
  const { id, ...data } = parsed.data;
  const payload = { ...data, art, imageUrl, imageAlt };
  if (id) {
    const before = await db.banner.findUnique({ where: { id }, select: { imageUrl: true } });
    await db.banner.update({ where: { id }, data: payload });
    if (before?.imageUrl && before.imageUrl !== imageUrl) await deleteStoredImage(before.imageUrl);
  } else await db.banner.create({ data: payload });
  refreshStorefront();
  back("/admin/banners");
}

export async function deleteBannerAction(formData: FormData) {
  await requireStaff("banners");
  const removed = await db.banner.delete({ where: { id: z.string().min(1).max(40).parse(formData.get("id")) } });
  await deleteStoredImage(removed.imageUrl);
  refreshStorefront();
  back("/admin/banners");
}
