"use server";

/** مدیریت مقاله‌های مجله: ذخیره (پیش‌نویس/انتشار)، حذف */
import { revalidatePath } from "next/cache";
import { z } from "zod";
import { db } from "@/lib/db";
import { slugifyFa } from "@/lib/persian";
import { storage } from "@/integrations/storage";
import { deleteStoredImage } from "@/server/services/images";
import { requireStaff } from "./guard";

const noTags = (s: string) => !/<\s*\/?\s*[a-z]/i.test(s);
const text = (label: string, min: number, max: number) =>
  z.string().trim().min(min, `${label} را وارد کنید`).max(max, `${label} حداکثر ${max} کاراکتر`).refine(noTags, "تگ HTML مجاز نیست");
const optional = (max: number) => z.string().trim().max(max).refine(noTags, "تگ HTML مجاز نیست").optional().transform((v) => v || null);
const internalOrHttps = z
  .string()
  .trim()
  .max(200)
  .refine((v) => !v || /^\/(?!\/)[^\s<>]*$/.test(v) || /^https:\/\/[^\s<>]+$/.test(v), "لینک باید آدرس داخلی (با /) یا https باشد")
  .optional()
  .transform((v) => v || null);

const articleSchema = z.object({
  title: text("عنوان", 5, 120),
  slug: z.string().trim().max(90).optional(),
  excerpt: text("خلاصه", 20, 300),
  body: text("متن مقاله", 50, 60_000),
  coverUrl: z.string().trim().max(300).optional().transform((v) => v || null),
  coverAlt: optional(140),
  seoTitle: optional(70),
  seoDescription: optional(170),
  focusKeyword: optional(60),
  faq: z.array(z.object({ q: text("پرسش", 5, 200), a: text("پاسخ", 10, 800) })).max(10),
  ctaLabel: optional(40),
  ctaHref: internalOrHttps,
  productIds: z.array(z.number().int().positive()).max(8),
  authorName: optional(60),
  publish: z.boolean(),
});

export type ArticleInput = z.input<typeof articleSchema>;
type Result = { ok: true; id: string } | { ok: false; errors: Record<string, string> };

export async function saveArticleAction(id: string | null, input: ArticleInput): Promise<Result> {
  await requireStaff("magazine");
  const parsed = articleSchema.safeParse(input);
  if (!parsed.success) {
    const errors: Record<string, string> = {};
    for (const i of parsed.error.issues) errors[i.path.join(".")] ??= i.message;
    return { ok: false, errors };
  }
  const { publish, slug: rawSlug, ...d } = parsed.data;
  const slug = slugifyFa(rawSlug || d.title).slice(0, 90);
  if (!slug) return { ok: false, errors: { slug: "اسلاگ نامعتبر است" } };
  // آدرس نباید آدرس فعلی یا قبلی مقاله دیگری باشد (ریدایرکت آن مقاله خراب می‌شد)
  const clash = await db.article.findFirst({ where: { OR: [{ slug }, { oldSlugs: { has: slug } }], ...(id ? { id: { not: id } } : {}) }, select: { id: true } });
  if (clash) return { ok: false, errors: { slug: "این آدرس برای مقاله دیگری (فعلی یا قبلی) استفاده شده است" } };
  if (d.coverUrl && !storage().keyFromUrl(d.coverUrl)) return { ok: false, errors: { coverUrl: "آدرس عکس نامعتبر است" } };
  if (d.ctaHref && !d.ctaLabel) return { ok: false, errors: { ctaLabel: "متن دکمه را وارد کنید" } };
  // فقط محصولات موجود
  const productIds = (await db.product.findMany({ where: { id: { in: d.productIds } }, select: { id: true } })).map((p) => p.id);

  const before = id ? await db.article.findUnique({ where: { id }, select: { status: true, publishedAt: true, coverUrl: true, slug: true, oldSlugs: true } }) : null;
  if (id && !before) return { ok: false, errors: { title: "مقاله پیدا نشد" } };
  const data = {
    ...d,
    slug,
    productIds,
    status: publish ? ("PUBLISHED" as const) : ("DRAFT" as const),
    // تاریخ انتشار فقط بار اولِ انتشار ثبت می‌شود
    publishedAt: publish ? (before?.publishedAt ?? new Date()) : (before?.publishedAt ?? null),
    // تغییر آدرس: آدرس قبلی نگه داشته می‌شود تا لینک‌های قدیمی و نتایج گوگل به آدرس جدید ریدایرکت شوند
    oldSlugs: before ? [...new Set([...before.oldSlugs, ...(before.slug !== slug ? [before.slug] : [])])].filter((s) => s !== slug) : [],
  };
  const saved = id ? await db.article.update({ where: { id }, data }) : await db.article.create({ data });
  if (before?.coverUrl && before.coverUrl !== d.coverUrl) await deleteStoredImage(before.coverUrl);

  revalidatePath("/mag");
  revalidatePath(`/mag/${slug}`);
  if (before && before.slug !== slug) revalidatePath(`/mag/${before.slug}`);
  revalidatePath("/sitemap.xml");
  return { ok: true, id: saved.id };
}

export async function deleteArticleAction(formData: FormData) {
  await requireStaff("magazine");
  const id = z.string().min(1).max(40).parse(formData.get("id"));
  const a = await db.article.delete({ where: { id } });
  await deleteStoredImage(a.coverUrl);
  revalidatePath("/mag");
  revalidatePath("/admin/magazine");
}
