/**
 * Runtime Guardrails for Revenue Suite
 * Enforces citations, approvals, and audit logging as per manifest requirements
 */
/**
 * Citation Validator
 * Ensures every claim has proper source attribution
 */
export class CitationValidator {
    /**
     * Validates that a response includes proper citations
     */
    validateCitations(response, citations) {
        if (citations.length === 0) {
            return {
                valid: false,
                coverage: 0,
                missing: ['No citations provided']
            };
        }
        // Check for citation markers in response (e.g., [1], [Source: ...])
        const citationMarkers = response.match(/\[(\d+|Source:.*?)\]/g) || [];
        // Check for factual claims without citations
        const claimPatterns = [
            /\b(according to|as stated in|referenced in|cited in)\b/gi,
            /\b(our policy|our documentation|our guide)\b/gi
        ];
        const hasClaimMarkers = claimPatterns.some(pattern => pattern.test(response));
        const hasCitations = citations.length > 0;
        if (hasClaimMarkers && !hasCitations) {
            return {
                valid: false,
                coverage: 0,
                missing: ['Claims detected but no citations provided']
            };
        }
        // Basic validation: ensure citations have required fields
        const invalidCitations = citations.filter(c => !c.sourceDoc);
        if (invalidCitations.length > 0) {
            return {
                valid: false,
                coverage: (citations.length - invalidCitations.length) / citations.length * 100,
                missing: invalidCitations.map((_, i) => `Citation ${i + 1} missing sourceDoc`)
            };
        }
        // All validations passed
        return {
            valid: true,
            coverage: 100,
            missing: []
        };
    }
    /**
     * Extracts citations from structured response
     */
    extractCitations(response) {
        if (typeof response === 'string') {
            // Parse citations from markdown-style references
            const citations = [];
            const citationRegex = /\[Source:\s*([^\]]+)\]/g;
            let match;
            while ((match = citationRegex.exec(response)) !== null) {
                const parts = match[1].split(',').map(p => p.trim());
                citations.push({
                    sourceDoc: parts[0],
                    section: parts[1],
                    version: parts[2]
                });
            }
            return citations;
        }
        // Handle structured response with citations array
        if (response && Array.isArray(response.citations)) {
            return response.citations;
        }
        return [];
    }
}
/**
 * Approval Manager
 * Handles human-in-the-loop approval workflows
 */
export class ApprovalManager {
    pendingApprovals = new Map();
    approvalHistory = new Map();
    /**
     * Request approval for a high-risk action
     */
    async requestApproval(actionType, actionDescription, riskLevel, requiredApprover, context) {
        const request = {
            id: `APPROVAL-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
            actionType,
            actionDescription,
            riskLevel,
            requiredApprover,
            context,
            requestedAt: new Date()
        };
        this.pendingApprovals.set(request.id, request);
        // Send notification to approver (email, Slack, webhook, etc.)
        console.log(`⚠️  Approval required: ${actionDescription}`);
        console.log(`   Approver: ${requiredApprover}`);
        console.log(`   Risk Level: ${riskLevel}`);
        console.log(`   Approval ID: ${request.id}`);
        // TODO: Implement actual notification system (email, Slack, webhook)
        return request;
    }
    /**
     * Record an approval response
     */
    async recordApproval(response) {
        this.approvalHistory.set(response.requestId, response);
        this.pendingApprovals.delete(response.requestId);
    }
    /**
     * Check if an action requires approval based on policy
     */
    requiresApproval(actionType, actionContext) {
        // Define approval policies
        const policies = [
            {
                condition: (type, ctx) => type === 'refund' && ctx.amount > 50000,
                approver: 'finance_director',
                riskLevel: 'high'
            },
            {
                condition: (type, ctx) => type === 'contract_edit',
                approver: 'legal_counsel',
                riskLevel: 'critical'
            },
            {
                condition: (type, ctx) => type === 'crm_update' && ctx.dealValue > 100000,
                approver: 'sales_director',
                riskLevel: 'medium'
            },
            {
                condition: (type, ctx) => type === 'data_export' && ctx.pii === true,
                approver: 'compliance_officer',
                riskLevel: 'high'
            }
        ];
        const matchedPolicy = policies.find(p => p.condition(actionType, actionContext));
        if (matchedPolicy) {
            return {
                required: true,
                approver: matchedPolicy.approver,
                riskLevel: matchedPolicy.riskLevel
            };
        }
        return { required: false };
    }
    /**
     * Get pending approval by ID
     */
    getPendingApproval(id) {
        return this.pendingApprovals.get(id);
    }
    /**
     * Get approval status
     */
    getApprovalStatus(id) {
        return this.approvalHistory.get(id);
    }
}
/**
 * Audit Logger
 * Logs all actions with inputs, outputs, and correlation IDs
 */
export class AuditLogger {
    logs = [];
    observabilityEndpoint;
    constructor(observabilityEndpoint) {
        this.observabilityEndpoint = observabilityEndpoint || process.env.OBSERVABILITY_ENDPOINT;
    }
    /**
     * Log an action with full context
     */
    async logAction(entry) {
        const fullEntry = {
            ...entry,
            id: `AUDIT-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
            timestamp: new Date()
        };
        // Redact PII from logs
        const redactedEntry = this.redactPII(fullEntry);
        // Store locally
        this.logs.push(redactedEntry);
        // Send to observability endpoint if configured
        if (this.observabilityEndpoint) {
            try {
                await this.sendToObservability(redactedEntry);
            }
            catch (error) {
                console.error('Failed to send audit log to observability endpoint:', error);
                // Continue - don't fail the action if logging fails
            }
        }
        // Also log to console for development
        console.log(`[AUDIT] ${redactedEntry.actionType}: ${redactedEntry.status}`);
        return fullEntry.id;
    }
    /**
     * Redact PII from audit logs
     */
    redactPII(entry) {
        const piiPatterns = [
            { regex: /\b\d{3}-\d{2}-\d{4}\b/g, replacement: 'SSN-REDACTED' }, // SSN
            { regex: /\b\d{16}\b/g, replacement: 'CC-REDACTED' }, // Credit card
            { regex: /\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b/g, replacement: 'EMAIL-REDACTED' } // Email (optional)
        ];
        const redactedEntry = { ...entry };
        // Redact inputs
        if (entry.inputs) {
            const inputsStr = JSON.stringify(entry.inputs);
            let redactedStr = inputsStr;
            for (const pattern of piiPatterns) {
                redactedStr = redactedStr.replace(pattern.regex, pattern.replacement);
            }
            redactedEntry.inputs = JSON.parse(redactedStr);
        }
        // Redact outputs
        if (entry.outputs) {
            const outputsStr = JSON.stringify(entry.outputs);
            let redactedStr = outputsStr;
            for (const pattern of piiPatterns) {
                redactedStr = redactedStr.replace(pattern.regex, pattern.replacement);
            }
            redactedEntry.outputs = JSON.parse(redactedStr);
        }
        return redactedEntry;
    }
    /**
     * Send audit log to external observability system
     */
    async sendToObservability(entry) {
        if (!this.observabilityEndpoint) {
            return;
        }
        // TODO: Implement actual HTTP POST to observability endpoint
        // Use fetch or axios
        console.log(`Sending audit log to ${this.observabilityEndpoint}:`, entry.id);
        // Example implementation:
        // await fetch(this.observabilityEndpoint, {
        //   method: 'POST',
        //   headers: { 'Content-Type': 'application/json' },
        //   body: JSON.stringify(entry)
        // });
    }
    /**
     * Query audit logs by correlation ID
     */
    getLogsByCorrelationId(correlationId) {
        return this.logs.filter(log => log.correlationId === correlationId);
    }
    /**
     * Query audit logs by user ID
     */
    getLogsByUserId(userId) {
        return this.logs.filter(log => log.userId === userId);
    }
    /**
     * Get all logs (for testing/debugging)
     */
    getAllLogs() {
        return [...this.logs];
    }
}
/**
 * Guardrails Orchestrator
 * Coordinates citation validation, approval flows, and audit logging
 */
export class GuardrailsOrchestrator {
    citationValidator;
    approvalManager;
    auditLogger;
    constructor(observabilityEndpoint) {
        this.citationValidator = new CitationValidator();
        this.approvalManager = new ApprovalManager();
        this.auditLogger = new AuditLogger(observabilityEndpoint);
    }
    getCitationValidator() {
        return this.citationValidator;
    }
    getApprovalManager() {
        return this.approvalManager;
    }
    getAuditLogger() {
        return this.auditLogger;
    }
    /**
     * Execute an action with full guardrail enforcement
     */
    async executeWithGuardrails(userId, correlationId, actionType, actionDescription, actionFn, inputs, options = {}) {
        // 1. Check if approval is required
        const approvalCheck = this.approvalManager.requiresApproval(actionType, inputs);
        if (approvalCheck.required) {
            const approvalRequest = await this.approvalManager.requestApproval(actionType, actionDescription, approvalCheck.riskLevel, approvalCheck.approver, inputs);
            // TODO: Wait for approval (implement polling or webhook callback)
            throw new Error(`Action requires approval from ${approvalCheck.approver}. ` +
                `Approval ID: ${approvalRequest.id}`);
        }
        // 2. Validate citations if required
        if (options.requireCitations) {
            const citationValidation = this.citationValidator.validateCitations(actionDescription, options.citations || []);
            if (!citationValidation.valid) {
                await this.auditLogger.logAction({
                    correlationId,
                    userId,
                    actionType,
                    actionDescription,
                    inputs,
                    status: 'failed',
                    errorMessage: `Citation validation failed: ${citationValidation.missing.join(', ')}`,
                    citations: options.citations
                });
                throw new Error(`Citation requirement not met: ${citationValidation.missing.join(', ')}`);
            }
        }
        // 3. Execute action with audit logging
        try {
            const result = await actionFn();
            await this.auditLogger.logAction({
                correlationId,
                userId,
                actionType,
                actionDescription,
                inputs,
                outputs: result,
                citations: options.citations,
                status: 'success'
            });
            return result;
        }
        catch (error) {
            await this.auditLogger.logAction({
                correlationId,
                userId,
                actionType,
                actionDescription,
                inputs,
                status: 'failed',
                errorMessage: error instanceof Error ? error.message : String(error),
                citations: options.citations
            });
            throw error;
        }
    }
}
// Singleton instance
let guardrailsInstance = null;
/**
 * Get or create the guardrails orchestrator instance
 */
export function getGuardrails(observabilityEndpoint) {
    if (!guardrailsInstance) {
        guardrailsInstance = new GuardrailsOrchestrator(observabilityEndpoint);
    }
    return guardrailsInstance;
}
//# sourceMappingURL=guardrails.js.map