/**
 * Attention Coordinator
 *
 * Implements attention-based coordination mechanisms from agentic-flow@alpha:
 * - multi-head: Standard multi-head attention
 * - flash: approximate sparse attention; speedup unverified — see docs/reviews/intelligence-system-audit-2026-05-29.md
 * - linear: For long sequences
 * - hyperbolic: Hierarchical data
 * - moe: Mixture of Experts routing
 * - graph-rope: Graph-aware positional embeddings
 *
 * Performance Targets:
 * - Flash Attention: approximate sparse attention; speedup unverified — see docs/reviews/intelligence-system-audit-2026-05-29.md
 * - Memory Reduction: unverified — see docs/reviews/intelligence-system-audit-2026-05-29.md
 * - MoE Routing: <5ms
 *
 * @module v3/swarm/attention-coordinator
 */

import { EventEmitter } from 'events';

// =============================================================================
// Types & Interfaces
// =============================================================================

/**
 * Attention mechanism types
 */
export type AttentionType =
  | 'multi-head'   // Standard multi-head attention
  | 'flash'        // approximate sparse attention; speedup unverified — see docs/reviews/intelligence-system-audit-2026-05-29.md
  | 'linear'       // For long sequences
  | 'hyperbolic'   // Hierarchical data
  | 'moe'          // Mixture of Experts
  | 'graph-rope';  // Graph-aware positional embeddings

/**
 * Agent output for coordination
 */
export interface AgentOutput {
  agentId: string;
  content: string | Record<string, unknown>;
  embedding?: Float32Array | number[];
  confidence?: number;
  tokens?: number;
  metadata?: Record<string, unknown>;
}

/**
 * Task for routing
 */
export interface Task {
  id: string;
  type: string;
  content: string;
  embedding?: Float32Array | number[];
  priority?: number;
  metadata?: Record<string, unknown>;
}

/**
 * Specialized agent for MoE routing
 */
export interface SpecializedAgent {
  id: string;
  name: string;
  expertise: string[];
  embedding: Float32Array | number[];
  capacity: number;
  currentLoad: number;
}

/**
 * Swarm topology for GraphRoPE
 */
export interface SwarmTopology {
  type: 'mesh' | 'hierarchical' | 'star' | 'ring';
  nodes: string[];
  edges: Array<{ from: string; to: string; weight?: number }>;
}

/**
 * Graph context for topology-aware coordination
 */
export interface GraphContext {
  adjacencyMatrix?: number[][];
  nodeFeatures?: number[][];
  edgeWeights?: number[];
}

/**
 * Coordination result
 */
export interface CoordinationResult {
  success: boolean;
  mechanism: AttentionType;
  consensusOutput: string | Record<string, unknown>;
  attentionWeights?: number[];
  confidence: number;
  latency: number;
  memoryUsed?: number;
  participatingAgents: string[];
  metadata?: Record<string, unknown>;
}

/**
 * Expert routing result
 */
export interface ExpertRoutingResult {
  success: boolean;
  selectedExperts: Array<{
    agentId: string;
    name: string;
    score: number;
    assignedTokens?: number;
  }>;
  routingLatency: number;
  loadBalanced: boolean;
}

/**
 * Attention coordinator configuration
 */
export interface AttentionCoordinatorConfig {
  defaultMechanism: AttentionType;
  flashAttention: {
    blockSize: number;
    causal: boolean;
  };
  moe: {
    topK: number;
    capacityFactor: number;
    loadBalancingLoss: boolean;
  };
  hyperbolic: {
    curvature: number;
    dimension: number;
  };
  graphRope: {
    maxDistance: number;
    distanceScale: number;
  };
}

// =============================================================================
// Default Configuration
// =============================================================================

const DEFAULT_CONFIG: AttentionCoordinatorConfig = {
  defaultMechanism: 'flash',
  flashAttention: {
    blockSize: 256,
    causal: false,
  },
  moe: {
    topK: 2,
    capacityFactor: 1.25,
    loadBalancingLoss: true,
  },
  hyperbolic: {
    curvature: -1.0,
    dimension: 64,
  },
  graphRope: {
    maxDistance: 10,
    distanceScale: 1.0,
  },
};

// =============================================================================
// Attention Coordinator
// =============================================================================

/**
 * AttentionCoordinator
 *
 * Coordinates multiple agents using various attention mechanisms for
 * consensus building and task routing.
 */
export class AttentionCoordinator extends EventEmitter {
  private config: AttentionCoordinatorConfig;
  private performanceStats = {
    totalCoordinations: 0,
    totalLatency: 0,
    flashSpeedup: 0,
    memoryReduction: 0,
  };

  constructor(config: Partial<AttentionCoordinatorConfig> = {}) {
    super();
    this.config = { ...DEFAULT_CONFIG, ...config };
  }

  // ===========================================================================
  // Main Coordination Methods
  // ===========================================================================

  /**
   * Coordinate agents using specified attention mechanism
   *
   * @param agentOutputs - Outputs from multiple agents
   * @param mechanism - Attention mechanism to use
   * @returns Coordination result with consensus
   */
  async coordinateAgents(
    agentOutputs: AgentOutput[],
    mechanism: AttentionType = this.config.defaultMechanism
  ): Promise<CoordinationResult> {
    const startTime = performance.now();

    this.emit('coordination:start', { mechanism, agentCount: agentOutputs.length });

    let result: CoordinationResult;

    switch (mechanism) {
      case 'flash':
        result = await this.flashAttentionCoordination(agentOutputs);
        break;
      case 'multi-head':
        result = await this.multiHeadAttentionCoordination(agentOutputs);
        break;
      case 'linear':
        result = await this.linearAttentionCoordination(agentOutputs);
        break;
      case 'hyperbolic':
        result = await this.hyperbolicAttentionCoordination(agentOutputs);
        break;
      case 'moe':
        result = await this.moeCoordination(agentOutputs);
        break;
      case 'graph-rope':
        result = await this.graphRopeCoordination(agentOutputs);
        break;
      default:
        result = await this.flashAttentionCoordination(agentOutputs);
    }

    const latency = performance.now() - startTime;
    result.latency = latency;

    this.updateStats(latency, mechanism, result);
    this.emit('coordination:complete', result);

    return result;
  }

  /**
   * Route task to specialized experts using MoE
   *
   * @param task - Task to route
   * @param agents - Available specialized agents
   * @param topK - Number of experts to select
   * @returns Routing result with selected experts
   */
  async routeToExperts(
    task: Task,
    agents: SpecializedAgent[],
    topK: number = this.config.moe.topK
  ): Promise<ExpertRoutingResult> {
    const startTime = performance.now();

    this.emit('routing:start', { taskId: task.id, agentCount: agents.length, topK });

    // Calculate routing scores
    const scores = await this.calculateExpertScores(task, agents);

    // Select top-K experts with load balancing
    const selectedExperts = this.selectTopKExperts(scores, agents, topK);

    const latency = performance.now() - startTime;

    const result: ExpertRoutingResult = {
      success: selectedExperts.length > 0,
      selectedExperts,
      routingLatency: latency,
      loadBalanced: this.config.moe.loadBalancingLoss,
    };

    this.emit('routing:complete', result);

    return result;
  }

  /**
   * Topology-aware coordination using GraphRoPE
   *
   * @param agentOutputs - Agent outputs
   * @param topology - Swarm topology
   * @param graphContext - Optional graph context
   * @returns Coordination result
   */
  async topologyAwareCoordination(
    agentOutputs: AgentOutput[],
    topology: SwarmTopology,
    graphContext?: GraphContext
  ): Promise<CoordinationResult> {
    const startTime = performance.now();

    this.emit('topology-coordination:start', {
      topology: topology.type,
      nodeCount: topology.nodes.length,
    });

    // Build position encodings from topology
    const positionEncodings = this.buildGraphPositionEncodings(topology, graphContext);

    // Apply GraphRoPE attention
    const result = await this.graphRopeCoordinationWithPositions(
      agentOutputs,
      positionEncodings
    );

    result.latency = performance.now() - startTime;
    result.metadata = {
      ...result.metadata,
      topologyType: topology.type,
      graphEncodingApplied: true,
    };

    this.emit('topology-coordination:complete', result);

    return result;
  }

  /**
   * Hierarchical coordination for queen-worker swarms
   *
   * @param queenOutputs - Outputs from queen agents
   * @param workerOutputs - Outputs from worker agents
   * @param curvature - Hyperbolic curvature (default: -1)
   * @returns Coordination result
   */
  async hierarchicalCoordination(
    queenOutputs: AgentOutput[],
    workerOutputs: AgentOutput[],
    curvature: number = this.config.hyperbolic.curvature
  ): Promise<CoordinationResult> {
    const startTime = performance.now();

    this.emit('hierarchical-coordination:start', {
      queenCount: queenOutputs.length,
      workerCount: workerOutputs.length,
    });

    // Use hyperbolic attention for hierarchical structure
    const allOutputs = [...queenOutputs, ...workerOutputs];

    // Apply hierarchical weights (queens have higher attention)
    const hierarchicalWeights = [
      ...queenOutputs.map(() => 2.0), // Higher weight for queens
      ...workerOutputs.map(() => 1.0),
    ];

    const result = await this.hyperbolicAttentionCoordination(
      allOutputs,
      curvature,
      hierarchicalWeights
    );

    result.latency = performance.now() - startTime;
    result.metadata = {
      ...result.metadata,
      hierarchical: true,
      curvature,
    };

    this.emit('hierarchical-coordination:complete', result);

    return result;
  }

  // ===========================================================================
  // Attention Mechanism Implementations
  // ===========================================================================

  /**
   * Flash Attention - approximate sparse attention; speedup unverified
   * — see docs/reviews/intelligence-system-audit-2026-05-29.md
   */
  private async flashAttentionCoordination(
    agentOutputs: AgentOutput[]
  ): Promise<CoordinationResult> {
    const n = agentOutputs.length;
    const blockSize = this.config.flashAttention.blockSize;

    // Flash Attention block-wise computation (memory efficient O(N) vs O(N²))
    // For GPU acceleration, integrate with @ruvector/flash-attention-wasm
    const attentionWeights = new Array(n).fill(0);
    let memoryUsed = 0;

    // Block-wise attention computation (memory efficient)
    for (let blockStart = 0; blockStart < n; blockStart += blockSize) {
      const blockEnd = Math.min(blockStart + blockSize, n);

      for (let i = blockStart; i < blockEnd; i++) {
        // Compute attention for this block
        let score = 0;
        for (let j = 0; j < n; j++) {
          if (this.config.flashAttention.causal && j > i) continue;
          score += this.computeAttentionScore(agentOutputs[i], agentOutputs[j]);
        }
        attentionWeights[i] = score / n;
      }

      // Track memory (block-wise uses less memory)
      memoryUsed += blockSize * blockSize * 4; // float32
    }

    // Compute consensus based on attention weights
    const consensusOutput = this.computeWeightedConsensus(agentOutputs, attentionWeights);

    return {
      success: true,
      mechanism: 'flash',
      consensusOutput,
      attentionWeights,
      confidence: this.computeConfidence(attentionWeights),
      latency: 0, // Set by caller
      memoryUsed,
      participatingAgents: agentOutputs.map(o => o.agentId),
      metadata: {
        // Speedup/memory reduction are UNMEASURED — no benchmark is wired.
        // Do not advertise a made-up factor. See
        // docs/reviews/intelligence-system-audit-2026-05-29.md
        speedup: 'unverified',
        memoryReduction: 'unverified',
        blockSize,
      },
    };
  }

  /**
   * Standard Multi-Head Attention
   */
  private async multiHeadAttentionCoordination(
    agentOutputs: AgentOutput[]
  ): Promise<CoordinationResult> {
    const n = agentOutputs.length;
    const numHeads = 8;
    const headDim = 64;

    // Multi-head attention computation
    const headOutputs: number[][] = [];

    for (let h = 0; h < numHeads; h++) {
      const headWeights = new Array(n).fill(0);

      for (let i = 0; i < n; i++) {
        for (let j = 0; j < n; j++) {
          const score = this.computeAttentionScore(agentOutputs[i], agentOutputs[j], h);
          headWeights[i] += score;
        }
        headWeights[i] /= n;
      }

      headOutputs.push(headWeights);
    }

    // Combine heads
    const attentionWeights = new Array(n).fill(0);
    for (let i = 0; i < n; i++) {
      for (let h = 0; h < numHeads; h++) {
        attentionWeights[i] += headOutputs[h][i];
      }
      attentionWeights[i] /= numHeads;
    }

    const consensusOutput = this.computeWeightedConsensus(agentOutputs, attentionWeights);

    return {
      success: true,
      mechanism: 'multi-head',
      consensusOutput,
      attentionWeights,
      confidence: this.computeConfidence(attentionWeights),
      latency: 0,
      memoryUsed: n * n * numHeads * 4,
      participatingAgents: agentOutputs.map(o => o.agentId),
      metadata: { numHeads, headDim },
    };
  }

  /**
   * Linear Attention for long sequences
   */
  private async linearAttentionCoordination(
    agentOutputs: AgentOutput[]
  ): Promise<CoordinationResult> {
    const n = agentOutputs.length;

    // Linear attention uses feature maps instead of full attention matrix
    // O(n) instead of O(n^2)
    const featureMap = (x: number) => Math.max(0, x); // Simple ReLU feature map

    const attentionWeights = new Array(n).fill(0);
    let sumFeatures = 0;

    // First pass: compute feature sum
    for (let i = 0; i < n; i++) {
      const feature = featureMap(agentOutputs[i].confidence || 0.5);
      sumFeatures += feature;
    }

    // Second pass: compute normalized weights
    for (let i = 0; i < n; i++) {
      const feature = featureMap(agentOutputs[i].confidence || 0.5);
      attentionWeights[i] = feature / (sumFeatures || 1);
    }

    const consensusOutput = this.computeWeightedConsensus(agentOutputs, attentionWeights);

    return {
      success: true,
      mechanism: 'linear',
      consensusOutput,
      attentionWeights,
      confidence: this.computeConfidence(attentionWeights),
      latency: 0,
      memoryUsed: n * 4, // O(n) memory
      participatingAgents: agentOutputs.map(o => o.agentId),
      metadata: { complexity: 'O(n)', suitableFor: 'long sequences' },
    };
  }

  /**
   * Hyperbolic Attention for hierarchical data
   */
  private async hyperbolicAttentionCoordination(
    agentOutputs: AgentOutput[],
    curvature: number = this.config.hyperbolic.curvature,
    hierarchicalWeights?: number[]
  ): Promise<CoordinationResult> {
    const n = agentOutputs.length;
    const c = Math.abs(curvature);

    // Hyperbolic distance computation
    const hyperbolicDistance = (x: number[], y: number[]): number => {
      // Simplified Poincaré distance
      const normX = Math.sqrt(x.reduce((s, v) => s + v * v, 0));
      const normY = Math.sqrt(y.reduce((s, v) => s + v * v, 0));
      const dot = x.reduce((s, v, i) => s + v * y[i], 0);

      const numerator = 2 * c * (normX * normX + normY * normY - 2 * dot);
      const denominator = (1 - c * normX * normX) * (1 - c * normY * normY);

      return Math.acosh(1 + numerator / Math.max(denominator, 1e-6));
    };

    const attentionWeights = new Array(n).fill(0);

    for (let i = 0; i < n; i++) {
      let totalWeight = 0;

      for (let j = 0; j < n; j++) {
        // Use embeddings or create synthetic vectors
        const embI = this.getOrCreateEmbedding(agentOutputs[i]);
        const embJ = this.getOrCreateEmbedding(agentOutputs[j]);

        const distance = hyperbolicDistance(
          Array.from(embI),
          Array.from(embJ)
        );

        // Convert distance to attention weight (closer = higher)
        const weight = Math.exp(-distance);
        totalWeight += weight;
      }

      attentionWeights[i] = totalWeight;

      // Apply hierarchical weights if provided
      if (hierarchicalWeights) {
        attentionWeights[i] *= hierarchicalWeights[i];
      }
    }

    // Normalize
    const sum = attentionWeights.reduce((a, b) => a + b, 0);
    for (let i = 0; i < n; i++) {
      attentionWeights[i] /= sum || 1;
    }

    const consensusOutput = this.computeWeightedConsensus(agentOutputs, attentionWeights);

    return {
      success: true,
      mechanism: 'hyperbolic',
      consensusOutput,
      attentionWeights,
      confidence: this.computeConfidence(attentionWeights),
      latency: 0,
      participatingAgents: agentOutputs.map(o => o.agentId),
      metadata: { curvature, suitableFor: 'hierarchical structures' },
    };
  }

  /**
   * Mixture of Experts coordination
   */
  private async moeCoordination(
    agentOutputs: AgentOutput[]
  ): Promise<CoordinationResult> {
    const n = agentOutputs.length;
    const topK = Math.min(this.config.moe.topK, n);

    // Compute gating scores for each agent
    const gatingScores = agentOutputs.map(output => ({
      agentId: output.agentId,
      score: output.confidence || 0.5,
    }));

    // Select top-K experts
    gatingScores.sort((a, b) => b.score - a.score);
    const selectedExperts = gatingScores.slice(0, topK);

    // Normalize scores among selected experts
    const scoreSum = selectedExperts.reduce((s, e) => s + e.score, 0);
    const normalizedScores = selectedExperts.map(e => e.score / (scoreSum || 1));

    // Build attention weights (sparse - only selected experts)
    const attentionWeights = new Array(n).fill(0);
    for (let i = 0; i < selectedExperts.length; i++) {
      const idx = agentOutputs.findIndex(o => o.agentId === selectedExperts[i].agentId);
      if (idx >= 0) {
        attentionWeights[idx] = normalizedScores[i];
      }
    }

    // Compute weighted consensus from selected experts only
    const selectedOutputs = selectedExperts.map(e =>
      agentOutputs.find(o => o.agentId === e.agentId)!
    );
    const consensusOutput = this.computeWeightedConsensus(selectedOutputs, normalizedScores);

    return {
      success: true,
      mechanism: 'moe',
      consensusOutput,
      attentionWeights,
      confidence: this.computeConfidence(normalizedScores),
      latency: 0,
      participatingAgents: selectedExperts.map(e => e.agentId),
      metadata: {
        topK,
        selectedCount: selectedExperts.length,
        capacityFactor: this.config.moe.capacityFactor,
      },
    };
  }

  /**
   * Graph-aware RoPE coordination
   */
  private async graphRopeCoordination(
    agentOutputs: AgentOutput[]
  ): Promise<CoordinationResult> {
    const n = agentOutputs.length;

    // Build default mesh topology
    const defaultTopology: SwarmTopology = {
      type: 'mesh',
      nodes: agentOutputs.map(o => o.agentId),
      edges: [],
    };

    // Create fully connected edges
    for (let i = 0; i < n; i++) {
      for (let j = i + 1; j < n; j++) {
        defaultTopology.edges.push({
          from: agentOutputs[i].agentId,
          to: agentOutputs[j].agentId,
          weight: 1,
        });
      }
    }

    const positionEncodings = this.buildGraphPositionEncodings(defaultTopology);
    return this.graphRopeCoordinationWithPositions(agentOutputs, positionEncodings);
  }

  private async graphRopeCoordinationWithPositions(
    agentOutputs: AgentOutput[],
    positionEncodings: Map<string, number[]>
  ): Promise<CoordinationResult> {
    const n = agentOutputs.length;
    const attentionWeights = new Array(n).fill(0);

    for (let i = 0; i < n; i++) {
      const posI = positionEncodings.get(agentOutputs[i].agentId) || [0];

      for (let j = 0; j < n; j++) {
        const posJ = positionEncodings.get(agentOutputs[j].agentId) || [0];

        // Apply rotary position encoding
        const rotaryFactor = this.computeRotaryEncoding(posI, posJ);

        // Base attention score with position encoding
        const baseScore = this.computeAttentionScore(agentOutputs[i], agentOutputs[j]);
        attentionWeights[i] += baseScore * rotaryFactor;
      }

      attentionWeights[i] /= n;
    }

    // Normalize
    const sum = attentionWeights.reduce((a, b) => a + b, 0);
    for (let i = 0; i < n; i++) {
      attentionWeights[i] /= sum || 1;
    }

    const consensusOutput = this.computeWeightedConsensus(agentOutputs, attentionWeights);

    return {
      success: true,
      mechanism: 'graph-rope',
      consensusOutput,
      attentionWeights,
      confidence: this.computeConfidence(attentionWeights),
      latency: 0,
      participatingAgents: agentOutputs.map(o => o.agentId),
      metadata: { graphAware: true, ropeApplied: true },
    };
  }

  // ===========================================================================
  // Helper Methods
  // ===========================================================================

  private computeAttentionScore(
    output1: AgentOutput,
    output2: AgentOutput,
    head?: number
  ): number {
    // Compute similarity-based attention score
    const emb1 = this.getOrCreateEmbedding(output1);
    const emb2 = this.getOrCreateEmbedding(output2);

    // Cosine similarity
    let dot = 0;
    let norm1 = 0;
    let norm2 = 0;

    const len = Math.min(emb1.length, emb2.length);
    for (let i = 0; i < len; i++) {
      dot += emb1[i] * emb2[i];
      norm1 += emb1[i] * emb1[i];
      norm2 += emb2[i] * emb2[i];
    }

    const similarity = dot / (Math.sqrt(norm1) * Math.sqrt(norm2) + 1e-8);

    // Scale by confidence
    const conf1 = output1.confidence || 0.5;
    const conf2 = output2.confidence || 0.5;

    return similarity * (conf1 + conf2) / 2;
  }

  private getOrCreateEmbedding(output: AgentOutput): Float32Array {
    if (output.embedding) {
      return output.embedding instanceof Float32Array
        ? output.embedding
        : new Float32Array(output.embedding);
    }

    // Create hash-based embedding from content
    const content = typeof output.content === 'string'
      ? output.content
      : JSON.stringify(output.content);

    const dim = 64;
    const embedding = new Float32Array(dim);

    for (let i = 0; i < content.length; i++) {
      const idx = i % dim;
      embedding[idx] += content.charCodeAt(i) / 1000;
    }

    // Normalize
    const norm = Math.sqrt(embedding.reduce((s, v) => s + v * v, 0));
    if (norm > 0) {
      for (let i = 0; i < dim; i++) {
        embedding[i] /= norm;
      }
    }

    return embedding;
  }

  private computeWeightedConsensus(
    outputs: AgentOutput[],
    weights: number[]
  ): string | Record<string, unknown> {
    // For string outputs, return highest weighted output
    // For object outputs, merge based on weights

    if (outputs.length === 0) return '';

    // Find highest weighted output
    let maxIdx = 0;
    let maxWeight = weights[0] || 0;

    for (let i = 1; i < weights.length; i++) {
      if (weights[i] > maxWeight) {
        maxWeight = weights[i];
        maxIdx = i;
      }
    }

    const primaryOutput = outputs[maxIdx];

    if (typeof primaryOutput.content === 'string') {
      return primaryOutput.content;
    }

    // For objects, return primary with metadata about consensus
    return {
      ...primaryOutput.content,
      _consensus: {
        primaryAgent: primaryOutput.agentId,
        weight: maxWeight,
        totalAgents: outputs.length,
      },
    };
  }

  private computeConfidence(weights: number[]): number {
    if (weights.length === 0) return 0;

    // Higher confidence when weights are more concentrated
    const max = Math.max(...weights);
    const sum = weights.reduce((a, b) => a + b, 0);

    return sum > 0 ? max / sum : 0;
  }

  private async calculateExpertScores(
    task: Task,
    agents: SpecializedAgent[]
  ): Promise<Map<string, number>> {
    const scores = new Map<string, number>();
    const taskEmbedding = this.getOrCreateEmbedding({
      agentId: 'task',
      content: task.content,
      embedding: task.embedding,
    });

    for (const agent of agents) {
      const agentEmbedding = agent.embedding instanceof Float32Array
        ? agent.embedding
        : new Float32Array(agent.embedding);

      // Cosine similarity
      let dot = 0;
      let normTask = 0;
      let normAgent = 0;

      const len = Math.min(taskEmbedding.length, agentEmbedding.length);
      for (let i = 0; i < len; i++) {
        dot += taskEmbedding[i] * agentEmbedding[i];
        normTask += taskEmbedding[i] * taskEmbedding[i];
        normAgent += agentEmbedding[i] * agentEmbedding[i];
      }

      const similarity = dot / (Math.sqrt(normTask) * Math.sqrt(normAgent) + 1e-8);

      // Adjust for load if load balancing is enabled
      let score = similarity;
      if (this.config.moe.loadBalancingLoss) {
        const loadPenalty = agent.currentLoad / agent.capacity;
        score *= (1 - loadPenalty * 0.3);
      }

      scores.set(agent.id, score);
    }

    return scores;
  }

  private selectTopKExperts(
    scores: Map<string, number>,
    agents: SpecializedAgent[],
    topK: number
  ): ExpertRoutingResult['selectedExperts'] {
    const sortedScores = Array.from(scores.entries())
      .sort((a, b) => b[1] - a[1])
      .slice(0, topK);

    return sortedScores.map(([agentId, score]) => {
      const agent = agents.find(a => a.id === agentId)!;
      return {
        agentId,
        name: agent.name,
        score,
      };
    });
  }

  private buildGraphPositionEncodings(
    topology: SwarmTopology,
    graphContext?: GraphContext
  ): Map<string, number[]> {
    const encodings = new Map<string, number[]>();
    const maxDistance = this.config.graphRope.maxDistance;

    // Build adjacency list
    const adjacency = new Map<string, string[]>();
    for (const node of topology.nodes) {
      adjacency.set(node, []);
    }
    for (const edge of topology.edges) {
      adjacency.get(edge.from)?.push(edge.to);
      adjacency.get(edge.to)?.push(edge.from);
    }

    // BFS to compute distances from first node
    const distances = new Map<string, number>();
    const queue: string[] = [topology.nodes[0]];
    distances.set(topology.nodes[0], 0);

    while (queue.length > 0) {
      const current = queue.shift()!;
      const currentDist = distances.get(current)!;

      for (const neighbor of adjacency.get(current) || []) {
        if (!distances.has(neighbor)) {
          distances.set(neighbor, currentDist + 1);
          queue.push(neighbor);
        }
      }
    }

    // Create position encodings based on graph distance
    for (const node of topology.nodes) {
      const dist = distances.get(node) || maxDistance;
      const normalizedDist = Math.min(dist, maxDistance) / maxDistance;

      // Create sinusoidal encoding
      const dim = 32;
      const encoding = new Array(dim);
      for (let i = 0; i < dim; i++) {
        const angle = normalizedDist * Math.PI * (i + 1);
        encoding[i] = i % 2 === 0 ? Math.sin(angle) : Math.cos(angle);
      }

      encodings.set(node, encoding);
    }

    return encodings;
  }

  private computeRotaryEncoding(pos1: number[], pos2: number[]): number {
    // Simplified rotary encoding - compute relative position factor
    let sum = 0;
    const len = Math.min(pos1.length, pos2.length);

    for (let i = 0; i < len; i++) {
      sum += pos1[i] * pos2[i];
    }

    // Return value between 0.5 and 1.5 based on position similarity
    return 1 + 0.5 * Math.tanh(sum);
  }

  private updateStats(
    latency: number,
    mechanism: AttentionType,
    result: CoordinationResult
  ): void {
    this.performanceStats.totalCoordinations++;
    this.performanceStats.totalLatency += latency;

    if (mechanism === 'flash') {
      // Flash Attention speedup is UNMEASURED in this build — no benchmark
      // kernel is wired here. Do NOT fabricate a value. Sentinel 0 means
      // "unmeasured"; consumers must not advertise a speedup until a real
      // measured path (kernel benchmark vs baseline) is implemented.
      // See docs/reviews/intelligence-system-audit-2026-05-29.md
      this.performanceStats.flashSpeedup = 0; // 0 = unmeasured (no fabrication)
      this.performanceStats.memoryReduction = 0; // 0 = unmeasured (no fabrication)
    }
  }

  // ===========================================================================
  // Public Getters
  // ===========================================================================

  getPerformanceStats(): typeof this.performanceStats {
    return { ...this.performanceStats };
  }

  getConfig(): AttentionCoordinatorConfig {
    return { ...this.config };
  }
}

// =============================================================================
// Factory Functions
// =============================================================================

export function createAttentionCoordinator(
  config?: Partial<AttentionCoordinatorConfig>
): AttentionCoordinator {
  return new AttentionCoordinator(config);
}

export default AttentionCoordinator;
