"use server";

import { auth } from "@/auth";
import { db } from "@/lib/db";
import { hasPermission } from "@/lib/permissions";
import { z } from "zod";
import bcrypt from "bcryptjs";
import { revalidatePath } from "next/cache";
import type { Role } from "@prisma/client";
import { ROLE_PREFIX, nextId } from "@/lib/id-generators";

type ActionResult = { ok: true } | { error: string };

const userSchema = z.object({
  name: z.string().min(1, "Name is required"),
  email: z.string().email("Invalid email"),
  role: z.enum(["TECHNICAL", "MANNING", "ACCOUNTS", "MANAGER", "SUPERUSER", "AUDITOR", "ADMIN"]),
  password: z.string().min(8, "Password must be at least 8 characters").optional(),
});

export async function createUser(formData: FormData): Promise<ActionResult> {
  const session = await auth();
  if (!session?.user || !hasPermission(session.user.role, "manage_users")) {
    return { error: "Unauthorized" };
  }

  const parsed = userSchema.safeParse({
    name: formData.get("name"),
    email: formData.get("email"),
    role: formData.get("role"),
    password: formData.get("password") || undefined,
  });
  if (!parsed.success) return { error: parsed.error.errors[0]?.message ?? "Validation failed" };

  const data = parsed.data;

  const exists = await db.user.findFirst({
    where: { email: data.email },
  });
  if (exists) return { error: "A user with that email already exists" };

  // Auto-generate employeeId based on role prefix
  const prefix = ROLE_PREFIX[data.role];
  const existingIds = await db.user.findMany({
    where: { role: data.role as Role },
    select: { employeeId: true },
  });
  const employeeId = nextId(prefix, existingIds.map((u) => u.employeeId));

  const passwordHash = data.password ? await bcrypt.hash(data.password, 12) : null;
  await db.user.create({
    data: {
      employeeId,
      name: data.name,
      email: data.email,
      role: data.role as Role,
      passwordHash,
    },
  });

  revalidatePath("/admin/users");
  return { ok: true };
}

export async function updateUser(formData: FormData): Promise<ActionResult> {
  const session = await auth();
  if (!session?.user || !hasPermission(session.user.role, "manage_users")) {
    return { error: "Unauthorized" };
  }

  const id = formData.get("id") as string;
  if (!id) return { error: "User ID is required" };

  const parsed = userSchema.safeParse({
    name: formData.get("name"),
    email: formData.get("email"),
    role: formData.get("role"),
    password: formData.get("password") || undefined,
  });
  if (!parsed.success) return { error: parsed.error.errors[0]?.message ?? "Validation failed" };

  const data = parsed.data;
  const conflict = await db.user.findFirst({
    where: {
      AND: [
        { id: { not: id } },
        { email: data.email },
      ],
    },
  });
  if (conflict) return { error: "Another user already has that email" };

  const updateData: Parameters<typeof db.user.update>[0]["data"] = {
    name: data.name,
    email: data.email,
    role: data.role as Role,
  };
  if (data.password) {
    updateData.passwordHash = await bcrypt.hash(data.password, 12);
  }

  await db.user.update({ where: { id }, data: updateData });
  revalidatePath("/admin/users");
  return { ok: true };
}

export async function deleteUser(id: string): Promise<ActionResult> {
  const session = await auth();
  if (!session?.user || !hasPermission(session.user.role, "manage_users")) return { error: "Unauthorized" };
  if (id === session.user.id) return { error: "Cannot delete your own account." };

  const hasPos = await db.purchaseOrder.findFirst({ where: { submitterId: id } });
  if (hasPos) return { error: "Cannot delete: user has submitted purchase orders. Deactivate them instead." };

  const hasActions = await db.pOAction.findFirst({ where: { actorId: id } });
  if (hasActions) return { error: "Cannot delete: user has purchase order activity on record. Deactivate them instead." };

  const hasConsumption = await db.itemConsumption.findFirst({ where: { recordedById: id } });
  if (hasConsumption) return { error: "Cannot delete: user has inventory consumption records. Deactivate them instead." };

  await db.$transaction(async (tx) => {
    await tx.notification.deleteMany({ where: { userId: id } });
    await tx.superUserRequest.deleteMany({
      where: { OR: [{ userId: id }, { resolvedById: id }] },
    });
    await tx.user.delete({ where: { id } });
  });

  revalidatePath("/admin/users");
  return { ok: true };
}

export async function toggleUserActive(userId: string): Promise<ActionResult> {
  const session = await auth();
  if (!session?.user || !hasPermission(session.user.role, "manage_users")) {
    return { error: "Unauthorized" };
  }
  if (userId === session.user.id) return { error: "You cannot deactivate your own account" };

  const user = await db.user.findUnique({ where: { id: userId }, select: { isActive: true } });
  if (!user) return { error: "User not found" };

  await db.user.update({ where: { id: userId }, data: { isActive: !user.isActive } });
  revalidatePath("/admin/users");
  return { ok: true };
}
