/**
 * PolicyEnforcementService — MissionPolicy enforcement logic
 *
 * Checks whether a given action is permitted under a Mission's policy,
 * and evaluates escalation rules against the current context.
 *
 * This service is called from the task delegation path, TaskPoolService,
 * and anywhere autonomy needs to be gated.
 *
 * @module services/policy/policy-enforcement.service
 */
import { ACTION_TO_POLICY_FIELD, isValidPolicyAction, } from '../../types/v2/index.js';
// ---------------------------------------------------------------------------
// PolicyEnforcementService
// ---------------------------------------------------------------------------
export class PolicyEnforcementService {
    /**
     * Checks whether an action is allowed under the given Mission's policy.
     *
     * @param action - The action being attempted
     * @param mission - The Mission whose policy governs this action
     * @param context - Optional escalation context for rule evaluation
     * @returns PolicyDecision indicating whether the action is allowed
     *
     * @example
     * ```typescript
     * const decision = service.checkPolicy('create_task', mission);
     * if (!decision.allowed) {
     *   console.log(`Blocked by ${decision.blockedBy}: ${decision.reason}`);
     * }
     * ```
     */
    checkPolicy(action, mission, context) {
        // Validate action
        if (!isValidPolicyAction(action)) {
            return {
                allowed: false,
                reason: `Unknown policy action: ${action}`,
            };
        }
        // Check the boolean gate
        const policyField = ACTION_TO_POLICY_FIELD[action];
        const isAllowed = mission.policy[policyField];
        if (!isAllowed) {
            return {
                allowed: false,
                reason: `Action '${action}' is not permitted by mission policy`,
                blockedBy: policyField,
            };
        }
        // Check escalation rules if context provided
        if (context) {
            const escalation = this.evaluateEscalationRules(mission.policy.escalationRules, context);
            if (escalation.triggered) {
                const blockingRule = escalation.triggeredRules.find(r => r.action === 'block');
                if (blockingRule) {
                    return {
                        allowed: false,
                        reason: `Escalation rule triggered: ${blockingRule.condition} exceeded threshold ${blockingRule.threshold}`,
                        escalation: blockingRule,
                    };
                }
                // Notify/pause don't block, but attach escalation info
                return {
                    allowed: true,
                    escalation: escalation.triggeredRules[0],
                };
            }
        }
        return { allowed: true };
    }
    /**
     * Checks whether a Mission has capacity for more parallel executions.
     *
     * @param mission - The Mission to check
     * @param currentExecutions - Number of currently running executions
     * @returns PolicyDecision indicating whether another execution is allowed
     */
    checkParallelCapacity(mission, currentExecutions) {
        if (currentExecutions >= mission.policy.maxParallelExecutions) {
            return {
                allowed: false,
                reason: `Parallel execution limit reached: ${currentExecutions}/${mission.policy.maxParallelExecutions}`,
                blockedBy: 'maxParallelExecutions',
            };
        }
        return { allowed: true };
    }
    /**
     * Evaluates escalation rules against the current context.
     *
     * @param rules - Escalation rules to evaluate
     * @param context - Current mission execution context
     * @returns EscalationResult with triggered rules and required action
     */
    evaluateEscalationRules(rules, context) {
        const triggeredRules = [];
        for (const rule of rules) {
            if (this.isRuleTriggered(rule, context)) {
                triggeredRules.push(rule);
            }
        }
        if (triggeredRules.length === 0) {
            return { triggered: false, triggeredRules: [] };
        }
        // Determine most severe action: block > pause > notify
        const severityOrder = ['block', 'pause', 'notify'];
        const requiredAction = severityOrder.find(action => triggeredRules.some(r => r.action === action));
        return {
            triggered: true,
            triggeredRules,
            requiredAction,
        };
    }
    /**
     * Performs a dry-run policy check — simulates without side effects.
     * Useful for the API dry-run endpoint.
     *
     * @param action - The action to simulate
     * @param policy - The policy to check against
     * @param context - Optional escalation context
     * @returns PolicyDecision (same as checkPolicy but guaranteed no side effects)
     */
    dryRunCheck(action, policy, context) {
        // Create a minimal Mission wrapper for the policy
        const fakeMission = {
            id: policy.missionId,
            objective: '',
            ownerTeamId: '',
            successCriteria: [],
            currentStrategy: '',
            activeProjectTaskIds: [],
            cadence: '',
            policy,
            status: 'active',
            createdAt: new Date().toISOString(),
            updatedAt: new Date().toISOString(),
            learnings: [],
        };
        return this.checkPolicy(action, fakeMission, context);
    }
    // -------------------------------------------------------------------------
    // Private
    // -------------------------------------------------------------------------
    /**
     * Checks whether a single escalation rule is triggered by the context.
     *
     * @param rule - The rule to evaluate
     * @param context - The execution context
     * @returns True if the rule's condition exceeds its threshold
     */
    isRuleTriggered(rule, context) {
        const conditionChecks = {
            cost_exceeded: () => context.currentCost !== undefined && context.currentCost > rule.threshold,
            time_exceeded: () => context.hoursElapsed !== undefined && context.hoursElapsed > rule.threshold,
            failure_count: () => context.failureCount !== undefined && context.failureCount > rule.threshold,
            scope_change: () => context.scopeChanged === true && rule.threshold <= 1,
            security_concern: () => context.securityConcern === true && rule.threshold <= 1,
        };
        const check = conditionChecks[rule.condition];
        return check ? check() : false;
    }
}
//# sourceMappingURL=policy-enforcement.service.js.map