/**
 * A2A Attestation Service
 *
 * Generates and processes attestations for agent-to-agent interactions.
 * Integrates with the Agent Anchor attestation system for trust scoring.
 *
 * @packageDocumentation
 */
import { createLogger } from '../common/logger.js';
const logger = createLogger({ component: 'a2a-attestation' });
// ============================================================================
// A2A Attestation Service
// ============================================================================
export class A2AAttestationService {
    pendingAttestations = [];
    callbacks = [];
    batchSize;
    flushIntervalMs;
    flushTimer = null;
    constructor(config = {}) {
        this.batchSize = config.batchSize ?? 50;
        this.flushIntervalMs = config.flushIntervalMs ?? 5000;
        logger.info({ batchSize: this.batchSize, flushIntervalMs: this.flushIntervalMs }, 'A2A attestation service initialized');
    }
    /**
     * Start periodic flushing
     */
    start() {
        if (this.flushTimer)
            return;
        this.flushTimer = setInterval(() => {
            this.flush().catch((err) => {
                logger.error({ error: err }, 'Failed to flush attestations');
            });
        }, this.flushIntervalMs);
        logger.info('A2A attestation service started');
    }
    /**
     * Stop periodic flushing
     */
    async stop() {
        if (this.flushTimer) {
            clearInterval(this.flushTimer);
            this.flushTimer = null;
        }
        // Flush remaining
        await this.flush();
        logger.info('A2A attestation service stopped');
    }
    /**
     * Register callback for attestation submission
     */
    onAttestation(callback) {
        this.callbacks.push(callback);
    }
    // ==========================================================================
    // Attestation Generation
    // ==========================================================================
    /**
     * Generate attestation from A2A invoke result
     */
    generateAttestation(request, response, durationMs) {
        const responsePayload = response?.payload;
        const invokePayload = request.payload;
        const outcome = this.determineOutcome(response, responsePayload);
        const violations = this.extractViolations(response, responsePayload);
        const attestationData = {
            callerCarId: request.from,
            calleeCarId: request.to,
            action: invokePayload.action || 'unknown',
            success: outcome === 'success',
            responseTimeMs: durationMs,
            trustNegotiated: !!request.trustContext.trustProof,
            trustRequirementsMet: outcome !== 'rejected',
            violations,
            chainDepth: request.trustContext.callChain.length + 1,
            delegationUsed: !!request.trustContext.delegation,
        };
        const attestation = {
            id: `a2a-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
            type: 'a2a_interaction',
            callerCarId: request.from,
            calleeCarId: request.to,
            action: invokePayload.action || 'unknown',
            requestId: request.id,
            rootRequestId: invokePayload.chainContext?.rootRequestId,
            outcome,
            data: attestationData,
            chain: {
                depth: request.trustContext.callChain.length + 1,
                trustFloor: this.calculateTrustFloor(request.trustContext.callChain),
                links: request.trustContext.callChain,
            },
            timestamp: new Date().toISOString(),
        };
        return attestation;
    }
    /**
     * Record an attestation
     */
    async record(attestation) {
        this.pendingAttestations.push(attestation);
        logger.debug({
            id: attestation.id,
            caller: attestation.callerCarId,
            callee: attestation.calleeCarId,
            outcome: attestation.outcome,
        }, 'Attestation recorded');
        // Flush if batch full
        if (this.pendingAttestations.length >= this.batchSize) {
            await this.flush();
        }
    }
    /**
     * Flush pending attestations
     */
    async flush() {
        if (this.pendingAttestations.length === 0) {
            return 0;
        }
        const batch = [...this.pendingAttestations];
        this.pendingAttestations = [];
        logger.info({ count: batch.length }, 'Flushing A2A attestations');
        // Submit to callbacks
        for (const callback of this.callbacks) {
            for (const attestation of batch) {
                try {
                    await callback(attestation);
                }
                catch (error) {
                    logger.error({ error, attestationId: attestation.id }, 'Callback failed');
                }
            }
        }
        return batch.length;
    }
    // ==========================================================================
    // Trust Impact Calculation
    // ==========================================================================
    /**
     * Calculate trust impact for both caller and callee
     */
    calculateTrustImpact(attestation) {
        const impacts = [];
        // Caller impact
        const callerImpact = this.calculateCallerImpact(attestation);
        if (callerImpact.scoreChange !== 0) {
            impacts.push(callerImpact);
        }
        // Callee impact
        const calleeImpact = this.calculateCalleeImpact(attestation);
        if (calleeImpact.scoreChange !== 0) {
            impacts.push(calleeImpact);
        }
        return impacts;
    }
    /**
     * Calculate caller trust impact
     */
    calculateCallerImpact(attestation) {
        const factors = {};
        let scoreChange = 0;
        // Successful calls build trust
        if (attestation.outcome === 'success') {
            factors['successful_call'] = 1;
            scoreChange += 1;
            // Bonus for deep chains (shows coordination ability)
            if (attestation.chain.depth > 2) {
                factors['chain_coordination'] = Math.min(attestation.chain.depth - 2, 3);
                scoreChange += factors['chain_coordination'];
            }
        }
        // Failures reduce trust slightly
        if (attestation.outcome === 'failure') {
            factors['failed_call'] = -1;
            scoreChange -= 1;
        }
        // Rejections (trust violations) are worse
        if (attestation.outcome === 'rejected') {
            factors['trust_rejection'] = -5;
            scoreChange -= 5;
        }
        // Violations
        const violationCount = attestation.data.violations.length;
        if (violationCount > 0) {
            factors['violations'] = -violationCount * 2;
            scoreChange += factors['violations'];
        }
        return {
            carId: attestation.callerCarId,
            scoreChange,
            reason: `A2A call to ${attestation.calleeCarId}: ${attestation.outcome}`,
            factors,
        };
    }
    /**
     * Calculate callee trust impact
     */
    calculateCalleeImpact(attestation) {
        const factors = {};
        let scoreChange = 0;
        // Successfully serving requests builds trust
        if (attestation.outcome === 'success') {
            factors['successful_service'] = 2;
            scoreChange += 2;
            // Fast responses are valued
            if (attestation.data.responseTimeMs < 100) {
                factors['fast_response'] = 1;
                scoreChange += 1;
            }
        }
        // Failures hurt callee reputation
        if (attestation.outcome === 'failure') {
            factors['service_failure'] = -2;
            scoreChange -= 2;
        }
        // Timeouts are worse
        if (attestation.outcome === 'timeout') {
            factors['timeout'] = -5;
            scoreChange -= 5;
        }
        return {
            carId: attestation.calleeCarId,
            scoreChange,
            reason: `A2A service to ${attestation.callerCarId}: ${attestation.outcome}`,
            factors,
        };
    }
    // ==========================================================================
    // Helpers
    // ==========================================================================
    /**
     * Determine outcome from response
     */
    determineOutcome(response, payload) {
        if (!response) {
            return 'timeout';
        }
        if (!payload) {
            return 'failure';
        }
        if (payload.error?.code === 'TRUST_INSUFFICIENT' ||
            payload.error?.code === 'CAPABILITY_DENIED') {
            return 'rejected';
        }
        if (payload.success) {
            return 'success';
        }
        return 'failure';
    }
    /**
     * Extract violations from response
     */
    extractViolations(response, payload) {
        const violations = [];
        if (!response || !payload) {
            return violations;
        }
        if (payload.error) {
            violations.push(`${payload.error.code}: ${payload.error.message}`);
        }
        return violations;
    }
    /**
     * Calculate trust floor from chain
     */
    calculateTrustFloor(chain) {
        if (chain.length === 0) {
            return 7; // Maximum if no chain
        }
        return Math.min(...chain.map((l) => l.tier));
    }
    // ==========================================================================
    // Analytics
    // ==========================================================================
    /**
     * Generate A2A analytics for an agent
     */
    generateAnalytics(attestations, carId) {
        const asCaller = attestations.filter((a) => a.callerCarId === carId);
        const asCallee = attestations.filter((a) => a.calleeCarId === carId);
        // Caller stats
        const asCallerStats = {
            total: asCaller.length,
            success: asCaller.filter((a) => a.outcome === 'success').length,
            failure: asCaller.filter((a) => a.outcome === 'failure').length,
            rejected: asCaller.filter((a) => a.outcome === 'rejected').length,
            timeout: asCaller.filter((a) => a.outcome === 'timeout').length,
        };
        // Callee stats
        const asCalleeStats = {
            total: asCallee.length,
            success: asCallee.filter((a) => a.outcome === 'success').length,
            failure: asCallee.filter((a) => a.outcome === 'failure').length,
            rejected: asCallee.filter((a) => a.outcome === 'rejected').length,
            timeout: asCallee.filter((a) => a.outcome === 'timeout').length,
        };
        // Top partners
        const partnerCounts = new Map();
        for (const a of asCaller) {
            partnerCounts.set(a.calleeCarId, (partnerCounts.get(a.calleeCarId) || 0) + 1);
        }
        for (const a of asCallee) {
            partnerCounts.set(a.callerCarId, (partnerCounts.get(a.callerCarId) || 0) + 1);
        }
        const topPartners = Array.from(partnerCounts.entries())
            .map(([carId, count]) => ({ carId, count }))
            .sort((a, b) => b.count - a.count)
            .slice(0, 10);
        // Avg response time (as callee)
        const responseTimes = asCallee
            .filter((a) => a.outcome === 'success')
            .map((a) => a.data.responseTimeMs);
        const avgResponseTime = responseTimes.length > 0
            ? responseTimes.reduce((a, b) => a + b, 0) / responseTimes.length
            : 0;
        // Overall success rate
        const totalInteractions = asCaller.length + asCallee.length;
        const successfulInteractions = asCaller.filter((a) => a.outcome === 'success').length +
            asCallee.filter((a) => a.outcome === 'success').length;
        const successRate = totalInteractions > 0 ? successfulInteractions / totalInteractions : 0;
        return {
            asCallerStats,
            asCalleeStats,
            topPartners,
            avgResponseTime,
            successRate,
        };
    }
    /**
     * Get pending attestation count
     */
    getPendingCount() {
        return this.pendingAttestations.length;
    }
}
// ============================================================================
// Factory Functions
// ============================================================================
let instance = null;
export function createA2AAttestationService(config) {
    if (!instance) {
        instance = new A2AAttestationService(config);
    }
    return instance;
}
export function getA2AAttestationService() {
    if (!instance) {
        throw new Error('A2AAttestationService not initialized');
    }
    return instance;
}
//# sourceMappingURL=attestation.js.map