"use server";

/** ایجاد/ویرایش محصول همراه با تنوع‌ها، و به‌روزرسانی موجودی */
import { revalidatePath } from "next/cache";
import { z } from "zod";
import { db } from "@/lib/db";
import { slugifyFa, toLatinDigits } from "@/lib/persian";
import { buildSearchText } from "@/lib/search-text";

import { refreshStorefront } from "./cache";
import { effectiveRate, getCurrencySettings, originalCategoryIds, tomanFromUsdCents } from "@/server/services/currency";
import { requireStaff } from "./guard";

const SHAPES = ["dropper", "bottle", "pump", "tube", "jar", "lipstick", "wand", "compact", "palette", "perfume"] as const;
const TAGS = ["new", "limited", "exclusive", "bestseller"] as const;
const hex = z.string().regex(/^#[0-9a-fA-F]{6}$/, "رنگ باید به شکل #RRGGBB باشد");
const text = (label: string, min: number, max: number) => z.string().trim().min(min, `${label} را وارد کنید`).max(max, `${label} حداکثر ${max} کاراکتر`);
const money = z.coerce.number().int("عدد صحیح وارد کنید").min(0).max(1_000_000_000);
/** قیمت دلاری (اعشار تا ۲ رقم) برای محصولات دسته «اورجینال»؛ خالی = ندارد */
const usd = z.preprocess(
  (v) => (v === "" || v == null ? undefined : typeof v === "string" ? Number(toLatinDigits(v).replace(/[,٬\s$]/g, "")) : v),
  z.number({ message: "قیمت دلاری را به عدد وارد کنید" }).positive("قیمت دلاری باید بیشتر از صفر باشد").max(100_000, "قیمت دلاری بیش از حد است").optional(),
);
const toCents = (n: number | undefined) => (n === undefined ? null : Math.round(n * 100));

const variantSchema = z
  .object({
    id: z.string().max(40).optional(),
    sku: z.string().trim().min(2, "SKU لازم است").max(40).regex(/^[A-Za-z0-9-_]+$/, "SKU فقط حروف لاتین، عدد و خط تیره"),
    colorName: z.string().trim().max(40).optional(),
    colorHex: hex.optional().or(z.literal("")),
    size: z.string().trim().max(40).optional(),
    // برای محصولات «اورجینال» قیمت تومان از روی قیمت دلاری محاسبه می‌شود و این مقدار نادیده گرفته می‌شود
    price: money,
    compareAtPrice: money.optional().or(z.literal("")),
    priceUsd: usd,
    compareAtUsd: usd,
    stock: z.coerce.number().int().min(0).max(100_000),
    isActive: z.boolean(),
  })
  .refine((v) => v.colorName || v.size, { message: "برای هر تنوع، رنگ یا حجم را وارد کنید", path: ["sku"] });

const productSchema = z.object({
  name: text("نام محصول", 3, 120),
  slug: z.string().trim().max(140).optional(),
  brandId: z.string().min(1, "برند را انتخاب کنید"),
  categoryId: z.string().min(1, "دسته را انتخاب کنید"),
  skinTypeIds: z.array(z.string()).max(5),
  summary: text("خلاصه", 5, 200),
  description: text("توضیحات", 10, 4000),
  howToUse: text("روش مصرف", 5, 2000),
  ingredients: text("ترکیبات", 3, 2000),
  // اختیاری: خالی مجاز است؛ اگر وارد شود باید ۱۰ تا ۲۰ رقم باشد
  ircCode: z
    .string()
    .optional()
    .transform((s) => toLatinDigits(s ?? "").replace(/\s/g, ""))
    .pipe(z.string().regex(/^(\d{10,20})?$/, "کد IRC باید ۱۰ تا ۲۰ رقم باشد (یا خالی بماند)")),
  madeIn: text("کشور سازنده", 2, 40),
  shape: z.enum(SHAPES),
  tone: hex,
  tags: z.array(z.enum(TAGS)).max(4),
  isActive: z.boolean(),
  variants: z.array(variantSchema).min(1, "حداقل یک تنوع لازم است").max(40),
});

export type ProductFormInput = z.input<typeof productSchema>;
export type SaveResult = { ok: true; id: number } | { ok: false; errors: Record<string, string> };

export async function saveProductAction(id: number | null, raw: ProductFormInput): Promise<SaveResult> {
  await requireStaff("products");
  const parsed = productSchema.safeParse(raw);
  if (!parsed.success) {
    // خطای تنوع‌ها با کلید variants.<index>.<field> برگردانده می‌شود
    const errors: Record<string, string> = {};
    for (const issue of parsed.error.issues) errors[issue.path.join(".")] ??= issue.message;
    return { ok: false, errors };
  }
  const d = parsed.data;
  const skus = d.variants.map((v) => v.sku.toUpperCase());
  if (new Set(skus).size !== skus.length) return { ok: false, errors: { variants: "SKU تکراری در تنوع‌ها" } };

  const [brand, category] = await Promise.all([
    db.brand.findUnique({ where: { id: d.brandId } }),
    db.category.findUnique({ where: { id: d.categoryId }, include: { parent: true } }),
  ]);
  if (!brand || !category) return { ok: false, errors: { brandId: "برند یا دسته نامعتبر است" } };

  // قیمت‌گذاری: «اورجینال» ← دلار × نرخ روز؛ بقیه دسته‌ها ← همان قیمت تومانی که مدیر وارد کرده
  const isOriginal = (await originalCategoryIds()).includes(category.id);
  const fxErrors: Record<string, string> = {};
  const fx = await getCurrencySettings();
  if (isOriginal && !effectiveRate(fx)) return { ok: false, errors: { variants: "نرخ دلار هنوز دریافت نشده؛ از بخش «نرخ دلار» بروزرسانی کنید یا نرخ دستی وارد کنید" } };
  for (const [i, v] of d.variants.entries()) {
    if (isOriginal) {
      if (v.priceUsd === undefined) fxErrors[`variants.${i}.priceUsd`] = "قیمت دلاری را وارد کنید";
      const t = v.priceUsd !== undefined ? tomanFromUsdCents(toCents(v.priceUsd)!, fx) : null;
      const c = v.compareAtUsd !== undefined ? tomanFromUsdCents(toCents(v.compareAtUsd)!, fx) : null;
      v.price = t ?? 0;
      v.compareAtPrice = c && t && c > t ? c : "";
    } else {
      if (v.price <= 0) fxErrors[`variants.${i}.price`] = "قیمت باید بیشتر از صفر باشد";
      v.priceUsd = undefined;
      v.compareAtUsd = undefined;
    }
  }
  if (Object.keys(fxErrors).length) return { ok: false, errors: fxErrors };

  // SKU نباید متعلق به محصول دیگری باشد
  const clash = await db.productVariant.findFirst({ where: { sku: { in: skus }, ...(id ? { productId: { not: id } } : {}) }, select: { sku: true } });
  if (clash) return { ok: false, errors: { variants: `SKU «${clash.sku}» برای محصول دیگری ثبت شده است` } };

  const active = d.variants.filter((v) => v.isActive);
  const data = {
    name: d.name,
    slug: slugifyFa(d.slug || d.name),
    brandId: d.brandId,
    categoryId: d.categoryId,
    summary: d.summary,
    description: d.description,
    howToUse: d.howToUse,
    ingredients: d.ingredients,
    ircCode: d.ircCode,
    madeIn: d.madeIn,
    shape: d.shape,
    tone: d.tone,
    tags: d.tags,
    isActive: d.isActive,
    minPrice: Math.min(...(active.length ? active : d.variants).map((v) => v.price)),
    searchText: buildSearchText({ name: d.name, summary: d.summary, brand, categories: [category.name, category.parent?.name ?? ""] }),
    skinTypes: { set: d.skinTypeIds.map((sid) => ({ id: sid })) },
  };

  const productId = await db.$transaction(async (tx) => {
    const product = id
      ? await tx.product.update({ where: { id }, data })
      : await tx.product.create({ data: { ...data, skinTypes: { connect: d.skinTypeIds.map((sid) => ({ id: sid })) } } });

    const existing = await tx.productVariant.findMany({ where: { productId: product.id }, select: { id: true, _count: { select: { orderItems: true } } } });
    const keep = new Set(d.variants.map((v) => v.id).filter(Boolean));
    // تنوع حذف‌شده: اگر در سفارشی استفاده شده، فقط غیرفعال می‌شود تا سابقه سفارش‌ها حفظ شود
    for (const e of existing.filter((e) => !keep.has(e.id))) {
      if (e._count.orderItems > 0) await tx.productVariant.update({ where: { id: e.id }, data: { isActive: false } });
      else await tx.productVariant.delete({ where: { id: e.id } });
    }
    for (const [i, v] of d.variants.entries()) {
      const vData = {
        sku: v.sku.toUpperCase(),
        colorName: v.colorName || null,
        colorHex: v.colorHex || null,
        size: v.size || null,
        price: v.price,
        compareAtPrice: v.compareAtPrice === "" || v.compareAtPrice === undefined ? null : v.compareAtPrice,
        priceUsdCents: toCents(v.priceUsd),
        compareAtUsdCents: toCents(v.compareAtUsd),
        stock: v.stock,
        isActive: v.isActive,
        sortOrder: i,
      };
      if (v.id && existing.some((e) => e.id === v.id)) await tx.productVariant.update({ where: { id: v.id }, data: vData });
      else await tx.productVariant.create({ data: { ...vData, productId: product.id } });
    }
    return product.id;
  });

  refreshStorefront();
  revalidatePath("/admin/products");
  return { ok: true, id: productId };
}

/** به‌روزرسانی سریع موجودی از صفحه موجودی */
export async function updateStockAction(formData: FormData) {
  await requireStaff(["products", "inventory"]);
  const input = z.object({ id: z.string().min(1).max(40), stock: z.coerce.number().int().min(0).max(100_000) }).parse({
    id: formData.get("id"),
    stock: toLatinDigits(String(formData.get("stock") ?? "")),
  });
  await db.productVariant.update({ where: { id: input.id }, data: { stock: input.stock } });
  refreshStorefront();
  revalidatePath("/admin/inventory");
}

export async function toggleProductAction(formData: FormData) {
  await requireStaff("products");
  const id = z.coerce.number().int().positive().parse(formData.get("id"));
  const p = await db.product.findUniqueOrThrow({ where: { id }, select: { isActive: true } });
  await db.product.update({ where: { id }, data: { isActive: !p.isActive } });
  refreshStorefront();
  revalidatePath("/admin/products");
}

