/**
 * @file ProcessPermissionsContext.tsx - Manages process-level permissions (AtAllowRights) for the currently authenticated user.
 * The permission set is populated when a process is selected and exposes helper functions to check whether the user holds a specific permission or combination of permissions.
 */

import type { AtAllowRight } from '../types/atAllowRights.ts';
import { createContext, useState, type ReactNode, useContext } from 'react';

/** Shape of the process permissions context value provided to consumers. */
type ProcessPermissionsContextType = {
  // Process permissions
  permissions: AtAllowRight[];
  setPermissions: (permissions: AtAllowRight[]) => void;

  // Functions to check whether user has given permissions
  hasPermission: (permission: AtAllowRight) => boolean;
  hasAnyPermission: (permissions: AtAllowRight[]) => boolean;
  hasAllPermissions: (permissions: AtAllowRight[]) => boolean;
};

const ProcessPermissionsContext = createContext<
  ProcessPermissionsContextType | undefined
>(undefined);

/**
 * Provider component that stores the current user's process-level permissions and exposes convenience helpers for permission checks.
 * Permissions are set when the user selects a process or loads a work item and are used throughout the processing UI to conditionally enable/disable features.
 *
 * @param children Child ReactNodes to be rendered within context
 */
export function ProcessPermissionsProvider({
  children,
}: {
  children: ReactNode;
}) {
  const [permissions, setPermissions] = useState<AtAllowRight[]>([]);

  /**
   * Checks whether the user has the provided permission.
   *
   * @param permission Process Director permission to validate
   * @returns True if the user has the permission, false otherwise
   */
  const hasPermission = (permission: AtAllowRight) => {
    return permissions.includes(permission);
  };

  /**
   * Checks whether the user has any of the provided permissions.
   *
   * @param requiredPermissions Process Director permissions to validate
   * @returns True if user has any permission, false otherwise
   */
  const hasAnyPermission = (requiredPermissions: AtAllowRight[]) => {
    return requiredPermissions.some((p) => permissions.includes(p));
  };

  /**
   * Checks whether the user has all the provided permissions.
   *
   * @param requiredPermissions Process Director permissions to validate
   * @returns True if user has all permissions, false otherwise
   */
  const hasAllPermissions = (requiredPermissions: AtAllowRight[]) => {
    return requiredPermissions.every((p) => permissions.includes(p));
  };

  return (
    <ProcessPermissionsContext.Provider
      value={{
        permissions,
        setPermissions,
        hasPermission,
        hasAnyPermission,
        hasAllPermissions,
      }}
    >
      {children}
    </ProcessPermissionsContext.Provider>
  );
}

/**
 * Hook to access the ProcessPermissionsContext. Must be called within a ProcessPermissionsProvider.
 *
 * @returns The current permissions array and permission-check helpers
 * @throws Error if called outside a ProcessPermissionsProvider
 */
export function useProcessPermissions() {
  const context = useContext(ProcessPermissionsContext);
  if (context === undefined) {
    throw new Error(
      'useProcessPermissions must be used within a ProcessPermissionsProvider'
    );
  }
  return context;
}
