import { redirect } from "next/navigation";
import { can, requireUser, type SessionUser } from "@/lib/auth";
import type { Department, Operation } from "@/lib/format";
import { getI18n } from "@/lib/i18n/server";

export type Actor = SessionUser & { motif?: string };

/**
 * Signed-in user allowed to run `operation` on `department`.
 * Pass the submitted form to record its `motif`: edits and deletes of existing records require one.
 */
export async function actor(department: Department, operation: Operation, formData?: FormData): Promise<Actor> {
  const user = await requireUser();
  if (!user) redirect("/login");
  if (!can(user, department, operation)) throw new Error((await getI18n()).t("You do not have permission for this action."));
  if (!formData) return user;
  const motif = String(formData.get("motif") ?? "").trim();
  if (!motif && (operation === "edit" || operation === "delete")) {
    throw await failure("A reason is required for every change.");
  }
  return { ...user, motif: motif || undefined };
}

/** A user-facing error in the viewer's language: `throw await failure("…")`. */
export async function failure(message: string, vars?: Record<string, string | number>) {
  return new Error((await getI18n()).t(message, vars));
}

/**
 * Deleting a record other records point to (a product with stock history, a driver with rounds)
 * is refused by the database. Say it in plain language instead of showing the database error.
 */
export async function removing<T>(what: string, run: () => Promise<T>): Promise<T> {
  try {
    return await run();
  } catch (error) {
    if ((error as { code?: string })?.code === "P2003") {
      throw await failure("{item} is used elsewhere and cannot be deleted. Deactivate it instead.", { item: what });
    }
    throw error;
  }
}
