"use server";

import { revalidatePath } from "next/cache";
import { redirect } from "next/navigation";
import { eq } from "drizzle-orm";
import { db } from "@/lib/db/client";
import { applications, users } from "@/lib/db/schema";
import { requireAdmin } from "@/lib/auth/admin-guard";
import { sendEmail } from "@/lib/email/send";
import { applicantApprovedEmail, applicantRejectedEmail } from "@/lib/email/templates";
import { logAdminAction } from "@/lib/audit";
import { loadEnv } from "@/lib/env";

export async function approveApplication(applicationId: string) {
  const session = await requireAdmin();
  const adminId = (session.user as { id?: string }).id!;
  const env = loadEnv();

  const [row] = await db
    .select({ app: applications, user: users })
    .from(applications)
    .innerJoin(users, eq(users.id, applications.userId))
    .where(eq(applications.id, applicationId))
    .limit(1);
  if (!row) throw new Error("Application not found");
  if (row.app.status !== "pending") throw new Error(`Already ${row.app.status}`);

  await db.update(applications).set({
    status: "approved",
    reviewedBy: adminId,
    reviewedAt: new Date(),
  }).where(eq(applications.id, applicationId));

  await db.update(users).set({
    status: "active",
    approvedAt: new Date(),
    approvedBy: adminId,
  }).where(eq(users.id, row.user.id));

  await sendEmail({ to: row.user.email, ...applicantApprovedEmail(row.user.name, `${env.nextAuthUrl}/login`) });
  await logAdminAction({ adminUserId: adminId, action: "approve_application", targetId: applicationId });

  revalidatePath("/admin/applications");
  redirect("/admin/applications");
}

// Cap at 2000 chars so an admin can't accidentally (or maliciously)
// store a novel in the notes column or bloat the applicant email.
const MAX_REJECTION_NOTES_LENGTH = 2000;

export async function rejectApplication(applicationId: string, notes: string) {
  const session = await requireAdmin();
  const adminId = (session.user as { id?: string }).id!;

  const cleanNotes = (notes ?? "").trim().slice(0, MAX_REJECTION_NOTES_LENGTH);

  const [row] = await db
    .select({ app: applications, user: users })
    .from(applications)
    .innerJoin(users, eq(users.id, applications.userId))
    .where(eq(applications.id, applicationId))
    .limit(1);
  if (!row) throw new Error("Application not found");
  if (row.app.status !== "pending") throw new Error(`Already ${row.app.status}`);

  await db.update(applications).set({
    status: "rejected",
    reviewedBy: adminId,
    reviewedAt: new Date(),
    reviewNotes: cleanNotes || null,
  }).where(eq(applications.id, applicationId));

  await db.update(users).set({ status: "rejected" }).where(eq(users.id, row.user.id));

  await sendEmail({ to: row.user.email, ...applicantRejectedEmail(row.user.name, cleanNotes || null) });
  await logAdminAction({ adminUserId: adminId, action: "reject_application", targetId: applicationId, metadata: { notes: cleanNotes } });

  revalidatePath("/admin/applications");
  redirect("/admin/applications");
}
