"use server";

import { revalidatePath } from "next/cache";
import { redirect } from "next/navigation";
import { requireTeacher } from "@/lib/auth/session";
import { prisma } from "@/lib/db/prisma";
import { profileSchema, settingSchema } from "@/lib/validation/profile";
import { mkdir, unlink, writeFile } from "node:fs/promises";
import path from "node:path";
import { randomUUID } from "node:crypto";

const value = (formData: FormData, key: string) => String(formData.get(key) ?? "");
const profileImageTypes = new Map([["image/jpeg", "jpg"], ["image/png", "png"], ["image/webp", "webp"]]);

function validProfileImage(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 === [137, 80, 78, 71, 13, 10, 26, 10][index]);
  if (type === "image/webp") return new TextDecoder().decode(bytes.slice(0, 4)) === "RIFF" && new TextDecoder().decode(bytes.slice(8, 12)) === "WEBP";
  return false;
}

export async function updateProfile(formData: FormData) {
  const session = await requireTeacher();
  const parsed = profileSchema.safeParse({ name: value(formData, "name"), title: value(formData, "title"), school: value(formData, "school"), department: value(formData, "department"), publicEmail: value(formData, "publicEmail"), bio: value(formData, "bio"), github: value(formData, "github"), youtube: value(formData, "youtube"), instagram: value(formData, "instagram"), linkedin: value(formData, "linkedin") });
  if (!parsed.success) redirect("/dashboard/profil?status=invalid");
  const { name, github, youtube, instagram, linkedin, ...profile } = parsed.data;
  const uploadedPhoto = formData.get("photo");
  let image: string | undefined;
  let oldImage: string | null = null;
  let newFilePath: string | null = null;
  if (uploadedPhoto instanceof File && uploadedPhoto.size > 0) {
    const extension = profileImageTypes.get(uploadedPhoto.type);
    if (!extension || uploadedPhoto.size > 5 * 1024 * 1024) redirect("/dashboard/profil?status=photo-invalid");
    const bytes = new Uint8Array(await uploadedPhoto.arrayBuffer());
    if (!validProfileImage(bytes, uploadedPhoto.type)) redirect("/dashboard/profil?status=photo-invalid");
    const directory = path.resolve(process.cwd(), "public", "uploads", "profiles");
    await mkdir(directory, { recursive: true });
    const filename = `${randomUUID()}.${extension}`;
    newFilePath = path.join(directory, filename);
    await writeFile(newFilePath, bytes, { flag: "wx" });
    image = `/uploads/profiles/${filename}`;
    const currentUser = await prisma.user.findUnique({ where: { id: session.user.id }, select: { image: true } });
    oldImage = currentUser?.image ?? null;
  }
  try {
    await prisma.$transaction([
      prisma.user.update({ where: { id: session.user.id }, data: { name, ...(image ? { image } : {}) } }),
      prisma.teacherProfile.upsert({ where: { userId: session.user.id }, update: { ...profile, publicEmail: profile.publicEmail || null, socialLinks: { github, youtube, instagram, linkedin } }, create: { userId: session.user.id, ...profile, publicEmail: profile.publicEmail || null, socialLinks: { github, youtube, instagram, linkedin } } }),
    ]);
  } catch (error) {
    if (newFilePath) await unlink(newFilePath).catch(() => undefined);
    throw error;
  }
  if (image && oldImage?.startsWith("/uploads/profiles/")) {
    const oldPath = path.resolve(process.cwd(), "public", oldImage.replace(/^\//, ""));
    const profileDirectory = path.resolve(process.cwd(), "public", "uploads", "profiles");
    if (oldPath.startsWith(`${profileDirectory}${path.sep}`)) await unlink(oldPath).catch(() => undefined);
  }
  revalidatePath("/"); revalidatePath("/tentang"); redirect("/dashboard/profil?status=saved");
}

export async function updateSettings(formData: FormData) {
  await requireTeacher();
  const parsed = settingSchema.safeParse({ websiteName: value(formData, "websiteName"), tagline: value(formData, "tagline"), footerText: value(formData, "footerText"), defaultTheme: value(formData, "defaultTheme") });
  if (!parsed.success) redirect("/dashboard/pengaturan?status=invalid");
  await prisma.setting.upsert({ where: { id: "site" }, update: parsed.data, create: { id: "site", ...parsed.data } });
  revalidatePath("/"); revalidatePath("/tentang"); redirect("/dashboard/pengaturan?status=saved");
}
