// SPDX-License-Identifier: Apache-2.0
// Copyright 2024-2026 Vorion LLC
/**
 * ENFORCE - Policy Decision Point
 *
 * Makes enforcement decisions based on rule evaluations, trust levels,
 * policy evaluation, constraint checking, and escalation rules.
 *
 * @packageDocumentation
 */
import { createLogger } from '../common/logger.js';
import { withSpan } from '../common/trace.js';
// Re-export all submodules
export * from './policy-engine.js';
export * from './constraint-evaluator.js';
export * from './escalation-rules.js';
export * from './decision-aggregator.js';
export * from './runtime-config.js';
// Import submodules for orchestration
import { createPolicyEngine, } from './policy-engine.js';
import { createConstraintEvaluator, InMemoryStateProvider, } from './constraint-evaluator.js';
import { createEscalationRuleEngine, } from './escalation-rules.js';
import { createDecisionAggregator, createSourceDecision, } from './decision-aggregator.js';
import { createRuntimeConfig, } from './runtime-config.js';
const logger = createLogger({ component: 'enforce' });
// =============================================================================
// ENFORCEMENT SERVICE
// =============================================================================
/**
 * Unified EnforcementService that orchestrates all enforcement components
 */
export class EnforcementService {
    policyEngine;
    constraintEvaluator;
    escalationEngine;
    decisionAggregator;
    runtimeConfig;
    legacyPolicy;
    options;
    constructor(options = {}) {
        this.policyEngine = createPolicyEngine(options.policyEngine);
        this.constraintEvaluator = createConstraintEvaluator(options.stateProvider ?? new InMemoryStateProvider(), options.constraintEvaluator);
        this.escalationEngine = createEscalationRuleEngine(options.escalationEngine);
        this.decisionAggregator = createDecisionAggregator(options.decisionAggregator);
        this.runtimeConfig = createRuntimeConfig(options.runtimeConfig);
        this.legacyPolicy = options.legacyPolicy ?? { defaultAction: 'deny' };
        this.options = {
            conflictStrategy: options.conflictStrategy ?? 'deny-overrides',
            enableTracing: options.enableTracing ?? true,
        };
        logger.info({
            conflictStrategy: this.options.conflictStrategy,
            enableTracing: this.options.enableTracing,
        }, 'Enforcement service initialized');
    }
    /**
     * Make an enforcement decision using all components
     */
    async decide(context) {
        const startTime = performance.now();
        const { intent, evaluation, trustScore, trustLevel } = context;
        // Check enforcement mode
        const mode = this.runtimeConfig.getEnforcementMode();
        if (mode === 'disabled') {
            return this.createDecision(intent.id, 'allow', evaluation.rulesEvaluated, trustScore, trustLevel);
        }
        // Collect decisions from all sources
        const sourceDecisions = [];
        // 1. Legacy policy evaluation
        const legacyDecision = this.evaluateLegacyPolicy(context);
        sourceDecisions.push(createSourceDecision({
            sourceId: 'legacy-policy',
            sourceType: 'policy-engine',
            sourceName: 'Legacy Policy',
            action: legacyDecision.action,
            confidence: 1.0,
            reason: legacyDecision.reason,
        }));
        // 2. Policy engine evaluation
        const policyContext = {
            intent,
            trustScore,
            trustLevel,
            context: intent.context,
        };
        const policyResults = this.policyEngine.evaluate(policyContext);
        for (const result of policyResults) {
            if (result.matched) {
                sourceDecisions.push(createSourceDecision({
                    sourceId: result.policyId,
                    sourceType: 'policy-engine',
                    sourceName: result.policyName,
                    action: result.action,
                    confidence: 1.0,
                    reason: `Policy matched: ${result.matchedRules.length} rules`,
                    constraints: result.appliedConstraints,
                    durationMs: result.durationMs,
                }));
            }
        }
        // 3. Constraint evaluation
        const constraintContext = {
            intent,
            trustScore,
            trustLevel,
            context: intent.context,
        };
        const constraintResults = await this.constraintEvaluator.evaluateAll(constraintContext);
        for (const result of constraintResults) {
            sourceDecisions.push(createSourceDecision({
                sourceId: result.constraintId,
                sourceType: 'constraint-evaluator',
                sourceName: result.constraintName,
                action: result.action,
                confidence: result.passed ? 1.0 : 0.9,
                reason: result.reason,
                details: result.details,
                durationMs: result.durationMs,
            }));
        }
        // 4. Escalation evaluation
        const escalationContext = {
            intent,
            trustScore,
            trustLevel,
            context: intent.context,
        };
        const escalationResult = this.escalationEngine.evaluate(escalationContext);
        if (escalationResult?.matched) {
            sourceDecisions.push(createSourceDecision({
                sourceId: escalationResult.rule.id,
                sourceType: 'escalation-engine',
                sourceName: `Escalation: ${escalationResult.rule.name}`,
                action: 'escalate',
                confidence: 1.0,
                reason: escalationResult.reason,
                details: {
                    riskScore: escalationResult.riskScore,
                    riskLevel: escalationResult.riskLevel,
                    targets: escalationResult.selectedTargets.map(t => t.name),
                },
            }));
        }
        // 5. Aggregate decisions
        const aggregationContext = {
            intent,
            trustScore,
            trustLevel,
            context: intent.context,
        };
        const aggregatedDecision = await this.decisionAggregator.aggregateWithTracing(sourceDecisions, aggregationContext, this.options.conflictStrategy);
        // Apply enforcement mode
        let finalAction = aggregatedDecision.action;
        if (mode === 'permissive' && finalAction === 'deny') {
            logger.info({ intentId: intent.id }, 'Permissive mode - logging violation but allowing');
            finalAction = 'allow';
        }
        else if (mode === 'shadow' || mode === 'audit-only') {
            logger.info({ intentId: intent.id, wouldBe: finalAction }, 'Shadow/audit mode - not enforcing');
            finalAction = 'allow';
        }
        const durationMs = performance.now() - startTime;
        logger.info({
            intentId: intent.id,
            action: finalAction,
            sourcesCount: sourceDecisions.length,
            hadConflict: aggregatedDecision.conflictResolution?.hadConflict ?? false,
            mode,
            durationMs,
        }, 'Enforcement decision made');
        // Create escalation if needed
        if (finalAction === 'escalate' && escalationResult) {
            const escalationRequest = await this.escalationEngine.createEscalation(escalationContext, escalationResult);
            return {
                intentId: intent.id,
                action: finalAction,
                constraintsEvaluated: this.mapConstraintResults(aggregatedDecision, evaluation),
                trustScore,
                trustLevel,
                escalation: {
                    id: escalationRequest.id,
                    intentId: intent.id,
                    reason: escalationRequest.reason,
                    escalatedTo: escalationRequest.escalatedTo,
                    timeout: escalationRequest.timeout,
                    status: escalationRequest.status,
                    createdAt: escalationRequest.createdAt,
                },
                decidedAt: new Date().toISOString(),
            };
        }
        return {
            intentId: intent.id,
            action: finalAction,
            constraintsEvaluated: this.mapConstraintResults(aggregatedDecision, evaluation),
            trustScore,
            trustLevel,
            decidedAt: new Date().toISOString(),
        };
    }
    /**
     * Decide with OpenTelemetry tracing
     */
    async decideWithTracing(context) {
        if (!this.options.enableTracing) {
            return this.decide(context);
        }
        return withSpan('enforce.decide', async (span) => {
            span.attributes['intent.id'] = context.intent.id;
            span.attributes['intent.goal'] = context.intent.goal;
            span.attributes['trust.level'] = context.trustLevel;
            span.attributes['trust.score'] = context.trustScore;
            span.attributes['enforcement.mode'] = this.runtimeConfig.getEnforcementMode();
            const decision = await this.decide(context);
            span.attributes['decision.action'] = decision.action;
            span.attributes['decision.hasEscalation'] = !!decision.escalation;
            return decision;
        }, { 'tenant.id': context.intent.tenantId });
    }
    /**
     * Evaluate legacy policy for backwards compatibility
     */
    evaluateLegacyPolicy(context) {
        const { intent, evaluation, trustLevel } = context;
        // Check minimum trust level
        if (this.legacyPolicy.requireMinTrustLevel !== undefined &&
            trustLevel < this.legacyPolicy.requireMinTrustLevel) {
            return {
                action: 'deny',
                reason: `Trust level ${trustLevel} insufficient, requires ${this.legacyPolicy.requireMinTrustLevel}`,
            };
        }
        // Use evaluation result action
        const action = evaluation.passed ? 'allow' : evaluation.finalAction;
        return {
            action,
            reason: evaluation.passed ? 'All rules passed' : 'Rules violated',
        };
    }
    /**
     * Map aggregated decision to constraint evaluation results
     */
    mapConstraintResults(aggregated, evaluation) {
        const results = [];
        // Include BASIS evaluation results
        for (const rule of evaluation.rulesEvaluated) {
            results.push({
                constraintId: rule.ruleId,
                passed: rule.matched,
                action: rule.action,
                reason: rule.reason,
                details: rule.details,
                durationMs: rule.durationMs,
                evaluatedAt: evaluation.evaluatedAt,
            });
        }
        // Include source decisions
        for (const source of aggregated.sourceDecisions) {
            results.push({
                constraintId: source.sourceId,
                passed: source.action === aggregated.action || source.action === 'allow',
                action: source.action,
                reason: source.reason,
                details: source.details ?? {},
                durationMs: source.durationMs ?? 0,
                evaluatedAt: source.decidedAt,
            });
        }
        return results;
    }
    /**
     * Create a decision record
     */
    createDecision(intentId, action, rulesEvaluated, trustScore, trustLevel) {
        return {
            intentId,
            action,
            constraintsEvaluated: rulesEvaluated.map((r) => ({
                constraintId: r.ruleId,
                passed: r.matched,
                action: r.action,
                reason: r.reason,
                details: r.details,
                durationMs: r.durationMs,
                evaluatedAt: new Date().toISOString(),
            })),
            trustScore,
            trustLevel,
            decidedAt: new Date().toISOString(),
        };
    }
    // =============================================================================
    // COMPONENT ACCESS
    // =============================================================================
    /**
     * Get the policy engine
     */
    getPolicyEngine() {
        return this.policyEngine;
    }
    /**
     * Get the constraint evaluator
     */
    getConstraintEvaluator() {
        return this.constraintEvaluator;
    }
    /**
     * Get the escalation engine
     */
    getEscalationEngine() {
        return this.escalationEngine;
    }
    /**
     * Get the decision aggregator
     */
    getDecisionAggregator() {
        return this.decisionAggregator;
    }
    /**
     * Get the runtime config
     */
    getRuntimeConfig() {
        return this.runtimeConfig;
    }
    // =============================================================================
    // POLICY MANAGEMENT (convenience methods)
    // =============================================================================
    /**
     * Add an enforcement policy
     */
    addPolicy(policy) {
        this.policyEngine.addPolicy(policy);
    }
    /**
     * Add a constraint
     */
    addConstraint(constraint) {
        this.constraintEvaluator.addConstraint(constraint);
    }
    /**
     * Add an escalation rule
     */
    addEscalationRule(rule) {
        this.escalationEngine.addRule(rule);
    }
    /**
     * Set enforcement mode
     */
    setEnforcementMode(mode) {
        this.runtimeConfig.setEnforcementMode(mode, 'enforcement-service');
    }
    /**
     * Get enforcement mode
     */
    getEnforcementMode() {
        return this.runtimeConfig.getEnforcementMode();
    }
    /**
     * Update legacy enforcement policy
     */
    setPolicy(policy) {
        this.legacyPolicy = policy;
        logger.info({ policy }, 'Legacy enforcement policy updated');
    }
    /**
     * Check if a feature flag is enabled
     */
    isFeatureEnabled(flagId, context) {
        return this.runtimeConfig.isFeatureEnabled(flagId, context);
    }
    // =============================================================================
    // STATISTICS
    // =============================================================================
    /**
     * Get service statistics
     */
    getStats() {
        return {
            policyEngine: this.policyEngine.getStats(),
            constraintEvaluator: this.constraintEvaluator.getStats(),
            escalationEngine: this.escalationEngine.getStats(),
            decisionAggregator: this.decisionAggregator.getStats(),
            runtimeConfig: this.runtimeConfig.getStats(),
        };
    }
    /**
     * Clear all components
     */
    clear() {
        this.policyEngine.clear();
        this.constraintEvaluator.clear();
        this.escalationEngine.clear();
        this.decisionAggregator.clearAudit();
        this.runtimeConfig.clear();
        logger.info('Enforcement service cleared');
    }
}
/**
 * Create a new enforcement service instance
 */
export function createEnforcementService(options) {
    return new EnforcementService(options);
}
//# sourceMappingURL=index.js.map