import {
  organizationRoleAccessRights,
  type OrganizationScope,
} from "@/src/features/rbac/constants/organizationAccessRights";
import { type Role } from "@langfuse/shared/src/db";
import { TRPCError } from "@trpc/server";
import { type Session } from "next-auth";
import { useSession } from "next-auth/react";

type HasOrganizationAccessParams =
  | {
      role: Role;
      scope: OrganizationScope;
      admin?: boolean; // prop user.admin
    }
  | {
      session: null | Session;
      organizationId: string;
      scope: OrganizationScope;
    };

/**
 * Check if user has access to the given scope, for use in TRPC resolvers
 * @throws TRPCError("FORBIDDEN") if user does not have access
 */
export const throwIfNoOrganizationAccess = (p: HasOrganizationAccessParams) => {
  if (!hasOrganizationAccess(p))
    throw new TRPCError({
      code: "FORBIDDEN",
      message:
        "Forbidden, user does not have access to this resource or action",
    });
};

/**
 * React hook to check if user has access to the given scope
 * @returns true if user has access, false otherwise or while loading
 */
export const useHasOrganizationAccess = (p: {
  organizationId: string | undefined;
  scope: OrganizationScope;
}) => {
  const { scope, organizationId } = p;
  const session = useSession();

  if (session.data?.user?.admin) return true;
  if (!organizationId) return false;

  return hasOrganizationAccess({
    session: session.data,
    scope,
    organizationId,
  });
};

// For use in UI components as function, if session is already available
export function hasOrganizationAccess(p: HasOrganizationAccessParams): boolean {
  const isAdmin = "role" in p ? p.admin : p.session?.user?.admin;
  if (isAdmin) return true;

  const organizationRole: Role | undefined =
    "role" in p
      ? p.role
      : p.session?.user?.organizations.find(
          (org) => org.id === p.organizationId,
        )?.role;
  if (organizationRole === undefined) return false;

  return organizationRoleAccessRights[organizationRole].includes(p.scope);
}
