import { createContext, useContext, ReactNode, Consumer } from 'react';
import { createContextualCan, BoundCanProps } from '@casl/react';
import { defineAbilitiesFor, AppAbility, User } from '@/lib/abilities';
import { useAuth } from './AuthContext';
import { AnyAbility } from '@casl/ability';

/**
 * CASL Ability Context
 */
const AbilityContext = createContext<AppAbility | undefined>(undefined);

/**
 * Can component for conditional rendering based on permissions
 *
 * @example
 * <Can I="create" a="VIP">
 *   <button>Add VIP</button>
 * </Can>
 *
 * @example
 * <Can I="update" a="ScheduleEvent">
 *   <button>Edit Event</button>
 * </Can>
 */
export const Can = createContextualCan(AbilityContext.Consumer as Consumer<AnyAbility>);

/**
 * Provider component that wraps the app with CASL abilities
 */
export function AbilityProvider({ children }: { children: ReactNode }) {
  const { backendUser } = useAuth();

  // Build abilities based on current user
  const ability = defineAbilitiesFor(backendUser as User | null);

  return (
    <AbilityContext.Provider value={ability}>
      {children}
    </AbilityContext.Provider>
  );
}

/**
 * Hook to access CASL ability in components
 *
 * @example
 * const ability = useAbility();
 * if (ability.can('create', 'VIP')) {
 *   // Show create button
 * }
 *
 * @example
 * const ability = useAbility();
 * const canEdit = ability.can('update', 'ScheduleEvent');
 */
export function useAbility(): AppAbility {
  const ability = useContext(AbilityContext);

  if (!ability) {
    throw new Error('useAbility must be used within an AbilityProvider');
  }

  return ability;
}
