// SolaceNet Service SDK - Capability Check Utilities

import { DbisError, ErrorCode } from '@/shared/types';
import { CapabilityState, EntitlementCheckContext, PolicyDecisionRequest } from './types';
import { policyEngineService } from '@/core/solacenet/policy/policy-engine.service';

/**
 * Service SDK for capability checks
 * Provides guard functions for services to check capability availability
 */

/**
 * Check if a capability is available for the given context
 * @param capabilityId - The capability ID to check
 * @param context - Context for entitlement check
 * @returns The capability state if available
 * @throws DbisError if capability is disabled or not available
 */
export async function checkCapability(
  capabilityId: string,
  context: EntitlementCheckContext
): Promise<CapabilityState> {
  try {
    const request: PolicyDecisionRequest = {
      tenantId: context.tenantId,
      programId: context.programId,
      capabilityId,
      region: context.region,
      channel: context.channel,
      actor: context.actor,
      context: {},
    };

    const decision = await policyEngineService.decide(request);

    if (!decision.allowed) {
      throw new DbisError(
        ErrorCode.FORBIDDEN,
        `Capability ${capabilityId} is not available: ${decision.reasonCode || decision.mode}`
      );
    }

    return decision.mode;
  } catch (error) {
    if (error instanceof DbisError) {
      throw error;
    }
    throw new DbisError(
      ErrorCode.INTERNAL_ERROR,
      `Failed to check capability: ${error instanceof Error ? error.message : 'Unknown error'}`
    );
  }
}

/**
 * Require a capability - throws if not available
 * @param capabilityId - The capability ID to require
 * @param context - Context for entitlement check
 * @throws DbisError if capability is disabled or not available
 */
export async function requireCapability(
  capabilityId: string,
  context: EntitlementCheckContext
): Promise<void> {
  await checkCapability(capabilityId, context);
}

/**
 * Get the current state of a capability without throwing
 * @param capabilityId - The capability ID to check
 * @param context - Context for entitlement check
 * @returns The capability state or null if check fails
 */
export async function getCapabilityState(
  capabilityId: string,
  context: EntitlementCheckContext
): Promise<CapabilityState | null> {
  try {
    return await checkCapability(capabilityId, context);
  } catch {
    return null;
  }
}
