import { auth } from "@/auth";
import { NextResponse } from "next/server";
import { can, type Permission } from "@/lib/rbac";
import type { Role } from "@prisma/client";

export type SessionUser = {
  id: string;
  name?: string | null;
  email?: string | null;
  role: Role;
  position: string | null;
};

/** Thrown by guards to short-circuit a route handler with an HTTP response. */
export class HttpError extends Error {
  constructor(public status: number, message: string) {
    super(message);
  }
}

/** Returns the current session user or throws 401. */
export async function requireUser(): Promise<SessionUser> {
  const session = await auth();
  if (!session?.user) throw new HttpError(401, "Not authenticated");
  return session.user as SessionUser;
}

/** Returns the current user, asserting they hold `perm`, else throws 403. */
export async function requirePermission(perm: Permission): Promise<SessionUser> {
  const user = await requireUser();
  if (!can(user.role, perm)) throw new HttpError(403, "Forbidden");
  return user;
}

/** Wrap a handler so HttpError is converted to a JSON response. */
export function withGuard<T extends unknown[]>(
  fn: (...args: T) => Promise<Response>
) {
  return async (...args: T): Promise<Response> => {
    try {
      return await fn(...args);
    } catch (err) {
      if (err instanceof HttpError) {
        return NextResponse.json({ error: err.message }, { status: err.status });
      }
      console.error("[api] unhandled error", err);
      return NextResponse.json(
        { error: "Internal server error" },
        { status: 500 }
      );
    }
  };
}
