import { TRPCError } from "@trpc/server";
import {
  PermissionKey,
  SystemRole,
  resolvePermissions,
  type PermissionOverrides,
} from "@capakraken/shared";
import type { TRPCContext } from "../trpc.js";

export type ResourceReadContext = Pick<TRPCContext, "db" | "dbUser" | "roleDefaults">;

export function resolveResourcePermissions(ctx: Pick<TRPCContext, "dbUser" | "roleDefaults">): Set<PermissionKey> {
  if (!ctx.dbUser) {
    return new Set();
  }

  return resolvePermissions(
    ctx.dbUser.systemRole as SystemRole,
    ctx.dbUser.permissionOverrides as PermissionOverrides | null,
    ctx.roleDefaults ?? undefined,
  );
}

export function canReadAllResources(ctx: Pick<TRPCContext, "dbUser" | "roleDefaults">): boolean {
  const permissions = resolveResourcePermissions(ctx);
  return permissions.has(PermissionKey.VIEW_ALL_RESOURCES) || permissions.has(PermissionKey.MANAGE_RESOURCES);
}

export async function findOwnedResourceId(ctx: ResourceReadContext): Promise<string | null> {
  if (!ctx.dbUser?.id) {
    return null;
  }

  if (!ctx.db.resource || typeof ctx.db.resource.findFirst !== "function") {
    return null;
  }

  const resource = await ctx.db.resource.findFirst({
    where: { userId: ctx.dbUser.id },
    select: { id: true },
  });

  return resource?.id ?? null;
}

export async function assertCanReadResource(
  ctx: ResourceReadContext,
  resourceId: string,
  message = "You can only view your own resource data",
): Promise<void> {
  if (canReadAllResources(ctx)) {
    return;
  }

  const ownedResourceId = await findOwnedResourceId(ctx);
  if (!ownedResourceId || ownedResourceId !== resourceId) {
    throw new TRPCError({
      code: "FORBIDDEN",
      message,
    });
  }
}
