"use server";

import { randomBytes } from "node:crypto";
import { revalidatePath } from "next/cache";
import { redirect } from "next/navigation";
import { Prisma } from "@prisma/client";
import { prisma } from "./prisma";
import { requireCurrentUser, userIsAdmin } from "./session";

async function requireAdmin() {
  const user = await requireCurrentUser();
  if (!userIsAdmin(user)) redirect("/dashboard");
  return user;
}

export async function disableUser(formData: FormData) {
  const admin = await requireAdmin();
  const userId = String(formData.get("userId") || "");
  if (!userId || userId === admin.id) return;
  await prisma.user.update({ where: { id: userId }, data: { disabledAt: new Date() } });
  await audit(admin.id, "admin.user.disable", { userId });
  revalidateAdmin();
}

export async function enableUser(formData: FormData) {
  const admin = await requireAdmin();
  const userId = String(formData.get("userId") || "");
  if (!userId) return;
  await prisma.user.update({ where: { id: userId }, data: { disabledAt: null } });
  await audit(admin.id, "admin.user.enable", { userId });
  revalidateAdmin();
}

export async function banUser(formData: FormData) {
  const admin = await requireAdmin();
  const userId = String(formData.get("userId") || "");
  if (!userId || userId === admin.id) return;

  const [friendships, memberships] = await prisma.$transaction([
    prisma.friendship.deleteMany({
      where: {
        OR: [{ requesterId: userId }, { receiverId: userId }]
      }
    }),
    prisma.roomMember.deleteMany({ where: { userId } }),
    prisma.user.update({ where: { id: userId }, data: { disabledAt: new Date() } })
  ]);

  await audit(admin.id, "admin.user.ban", {
    userId,
    removedFriendships: friendships.count,
    removedRoomMemberships: memberships.count
  });
  revalidateAdmin();
}

export async function removeUserFriendships(formData: FormData) {
  const admin = await requireAdmin();
  const userId = String(formData.get("userId") || "");
  if (!userId || userId === admin.id) return;

  const result = await prisma.friendship.deleteMany({
    where: {
      OR: [{ requesterId: userId }, { receiverId: userId }]
    }
  });

  await audit(admin.id, "admin.user.friendships.remove", { userId, removedFriendships: result.count });
  revalidateAdmin();
}

export async function grantAdminRole(formData: FormData) {
  const admin = await requireAdmin();
  const userId = String(formData.get("userId") || "");
  if (!userId) return;
  const role = await prisma.role.upsert({
    where: { name: "admin" },
    update: {},
    create: { name: "admin", description: "Full system administrator" }
  });
  await prisma.userRole.upsert({
    where: { userId_roleId: { userId, roleId: role.id } },
    update: {},
    create: { userId, roleId: role.id }
  });
  await audit(admin.id, "admin.user.role.grant", { userId, role: "admin" });
  revalidateAdmin();
}

export async function revokeAdminRole(formData: FormData) {
  const admin = await requireAdmin();
  const userId = String(formData.get("userId") || "");
  if (!userId || userId === admin.id) return;
  const role = await prisma.role.findUnique({ where: { name: "admin" } });
  if (!role) return;
  await prisma.userRole.deleteMany({ where: { userId, roleId: role.id } });
  await audit(admin.id, "admin.user.role.revoke", { userId, role: "admin" });
  revalidateAdmin();
}

export async function createInstanceInvite(formData: FormData) {
  const admin = await requireAdmin();
  const roomId = String(formData.get("roomId") || "") || null;
  const expiresDays = Number(formData.get("expiresDays") || 0);
  const expiresAt = Number.isFinite(expiresDays) && expiresDays > 0 ? new Date(Date.now() + expiresDays * 24 * 60 * 60 * 1000) : null;
  const invite = await prisma.invite.create({
    data: {
      code: randomBytes(12).toString("base64url"),
      creatorId: admin.id,
      roomId,
      expiresAt
    }
  });
  await audit(admin.id, "admin.invite.create", { inviteId: invite.id, roomId });
  revalidateAdmin();
  redirect("/admin?tab=Invites&saved=1");
}

export async function revokeInvite(formData: FormData) {
  const admin = await requireAdmin();
  const inviteId = String(formData.get("inviteId") || "");
  if (!inviteId) return;
  await prisma.invite.update({ where: { id: inviteId }, data: { status: "REVOKED" } });
  await audit(admin.id, "admin.invite.revoke", { inviteId });
  revalidateAdmin();
}

async function audit(actorId: string, action: string, metadata: Prisma.InputJsonObject) {
  await prisma.auditEvent.create({ data: { actorId, action, metadata } });
}

function revalidateAdmin() {
  revalidatePath("/admin");
  revalidatePath("/dashboard");
  revalidatePath("/rooms");
}
