import { IiosPlatformPorts, PolicyDecision, PolicyDeniedError } from '@insignia/iios-contracts';

/**
 * Fail-closed authorization (Bottom-Up hard gate; Critics KG-03).
 *
 * Calls the OPA port. The kernel proceeds ONLY on an explicit allow. A denial,
 * a thrown error, or a timeout all become a PolicyDeniedError — never an
 * implicit allow. Callers must let this propagate so nothing is written.
 */
export async function decideOrThrow(ports: IiosPlatformPorts, input: unknown): Promise<PolicyDecision> {
  let decision: PolicyDecision;
  try {
    decision = await ports.opa.decide(input);
  } catch (err) {
    throw new PolicyDeniedError(`policy port unavailable: ${(err as Error).message}`);
  }
  if (!decision.allow) {
    throw new PolicyDeniedError(decision.obligations[0]?.reason ?? 'policy denied');
  }
  return decision;
}
