"use server";

import { randomUUID } from "node:crypto";
import { mkdir, unlink, writeFile } from "node:fs/promises";
import path from "node:path";
import { revalidatePath } from "next/cache";
import { redirect } from "next/navigation";
import { z } from "zod";
import { requireTeacher } from "@/lib/auth/session";
import { prisma } from "@/lib/db/prisma";
import { notifyActiveStudents } from "@/lib/notifications";

const articleSchema = z.object({
  title: z.string().trim().min(3).max(191), excerpt: z.string().trim().max(500),
  categoryId: z.string().min(1), subjectId: z.string(), status: z.enum(["DRAFT", "PUBLISHED"]),
  content: z.string().min(2),
});
const uploadsDirectory = path.resolve(process.cwd(), "public", "uploads", "articles");
const fileTypes = new Map([["image/jpeg", "jpg"], ["image/png", "png"], ["image/webp", "webp"]]);
const value = (data: FormData, key: string) => String(data.get(key) ?? "").trim();
const slugify = (input: string) => input.toLowerCase().normalize("NFKD").replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "") || "artikel";

function hasValidSignature(bytes: Uint8Array, type: string) {
  if (type === "image/jpeg") return bytes[0] === 0xff && bytes[1] === 0xd8 && bytes[2] === 0xff;
  if (type === "image/png") return bytes.slice(0, 8).every((byte, index) => byte === [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a][index]);
  if (type === "image/webp") return new TextDecoder().decode(bytes.slice(0, 4)) === "RIFF" && new TextDecoder().decode(bytes.slice(8, 12)) === "WEBP";
  return false;
}
async function removeLocalCover(cover: string | null | undefined) {
  if (!cover?.startsWith("/uploads/articles/")) return;
  const target = path.resolve(process.cwd(), "public", cover.replace(/^\//, ""));
  if (target.startsWith(`${uploadsDirectory}${path.sep}`)) await unlink(target).catch(() => undefined);
}

export async function saveArticle(formData: FormData) {
  const session = await requireTeacher();
  const id = value(formData, "id");
  const parsed = articleSchema.safeParse(Object.fromEntries(formData));
  if (!parsed.success) redirect(`/dashboard/artikel/${id ? `${id}/edit` : "baru"}?error=invalid`);
  let content: object;
  try { content = JSON.parse(parsed.data.content) as object; } catch { redirect(`/dashboard/artikel/${id ? `${id}/edit` : "baru"}?error=content`); }
  const existing = id ? await prisma.article.findUnique({ where: { id } }) : null;
  if (id && !existing) redirect("/dashboard/artikel");

  const upload = formData.get("cover");
  let newCover: string | undefined;
  if (upload instanceof File && upload.size > 0) {
    const extension = fileTypes.get(upload.type);
    if (!extension || upload.size > 5 * 1024 * 1024) redirect(`/dashboard/artikel/${id ? `${id}/edit` : "baru"}?error=cover`);
    const bytes = new Uint8Array(await upload.arrayBuffer());
    if (!hasValidSignature(bytes, upload.type)) redirect(`/dashboard/artikel/${id ? `${id}/edit` : "baru"}?error=cover`);
    await mkdir(uploadsDirectory, { recursive: true });
    const filename = `${randomUUID()}.${extension}`;
    await writeFile(path.join(uploadsDirectory, filename), bytes, { flag: "wx" });
    newCover = `/uploads/articles/${filename}`;
  }

  const shouldRemoveCover = value(formData, "removeCover") === "1";
  const articleSlug = existing?.slug ?? `${slugify(parsed.data.title)}-${randomUUID().slice(0, 8)}`;
  const common = { title: parsed.data.title, excerpt: parsed.data.excerpt || null, categoryId: parsed.data.categoryId, subjectId: parsed.data.subjectId || null, status: parsed.data.status, content, publishedAt: parsed.data.status === "PUBLISHED" ? existing?.publishedAt ?? new Date() : null };
  try {
    if (existing) await prisma.article.update({ where: { id }, data: { ...common, ...(newCover || shouldRemoveCover ? { cover: newCover ?? null } : {}) } });
    else await prisma.article.create({ data: { ...common, slug: articleSlug, authorId: session.user.id, cover: newCover } });
  } catch (error) { if (newCover) await removeLocalCover(newCover); throw error; }
  if (existing?.cover && (newCover || shouldRemoveCover)) await removeLocalCover(existing.cover);
  if (parsed.data.status === "PUBLISHED" && existing?.status !== "PUBLISHED") await notifyActiveStudents({ title: "Artikel baru diterbitkan", message: parsed.data.title, type: "ARTICLE", href: `/artikel/${articleSlug}` });
  revalidatePath("/artikel"); revalidatePath("/dashboard/artikel");
  redirect("/dashboard/artikel");
}

export async function deleteArticle(formData: FormData) {
  await requireTeacher();
  const article = await prisma.article.findUnique({ where: { id: value(formData, "id") }, select: { id: true, cover: true } });
  if (article) { await prisma.article.delete({ where: { id: article.id } }); await removeLocalCover(article.cover); }
  revalidatePath("/artikel"); revalidatePath("/dashboard/artikel");
}
