/**
 * ⚠️ SHELVED / NOT A PRODUCTION CAPABILITY (2026-07-27) — READ FIRST:
 * This implements edge↔cloud failover for a CENTRAL-CLOUD topology. Production is standalone-per-bank;
 * there is NO central cloud, so this is NOT a production capability and is NOT wired to any production
 * path or UI. RETAINED only because chaosEngine (partition test) consumes it directly via
 * getHeartbeatMonitor(). Its former HTTP routes (/api/cloud/*, /api/edge/*, root /heartbeat + /sync
 * aliases) and the sovereign-edge UI were REMOVED 2026-07-27 — consumer-less, and /api/cloud/sync + /sync
 * were UNAUTHENTICATED accept-all forged-write surfaces. If this is ever wired for a real multi-node /
 * edge-cloud topology, REBUILD the routes with real auth and real PQC verify — do NOT resurrect the
 * accept-all verify. (Offline-moat reconciliation, project memory 2026-07-27.)
 */

/**
 * Heartbeat Monitor - Autonomous Failover Trigger
 * Detects network partition and manages state transitions
 * 
 * Patent Reference: AEGIS-PAT-2026-001
 * Component: Autonomous Failover Trigger (S502-S516)
 * 
 * Timing Specifications:
 * - Heartbeat Interval: 100ms
 * - Detection Threshold: 5 consecutive misses (500ms)
 * - HLC Activation: <10ms
 * - State Transition: <100ms
 * - Total Failover: <500ms
 */

import { HLC, getGlobalClock } from './hlc';
import { SyncManager, getSyncManager, PendingTransaction } from './syncManager';
import { EventEmitter } from 'events';
import { getPQCEngine, MLKEMEngine } from './pqcEngine';
import { 
  getCommercialHeartbeat, 
  CommercialMeshHeartbeat,
  SentinelSelfHealing,
  LatticeIdentityManager,
  EphemeralVaultManager,
  CausalShardingManager,
  SovereignIsolationManager
} from './commercialGrade';
import { logger } from './lib/logger';

const heartbeatLogger = logger.child('heartbeat');

export type SystemMode = 'CLOUD_MODE' | 'SOVEREIGN_MODE' | 'TRANSITIONING';

export interface HeartbeatStatus {
  mode: SystemMode;
  consecutiveMisses: number;
  lastHeartbeat: Date | null;
  lastModeChange: Date;
  uptimeSeconds: number;
  transactionsProcessed: number;
  pendingSyncCount: number;
}

export interface HeartbeatConfig {
  cloudApiUrl: string;
  nodeId: string;
  heartbeatIntervalMs: number;
  missThreshold: number;
  heartbeatTimeoutMs: number;
}

const DEFAULT_CONFIG: HeartbeatConfig = {
  cloudApiUrl: process.env.CLOUD_API_URL || 'http://localhost:3001',
  nodeId: process.env.EDGE_NODE_ID || 'edge-node-001',
  heartbeatIntervalMs: 100,      // 100ms interval
  missThreshold: 5,               // 5 consecutive misses = 500ms
  heartbeatTimeoutMs: 80          // Response must arrive within 80ms
};

export class HeartbeatMonitor extends EventEmitter {
  private config: HeartbeatConfig;
  private mode: SystemMode = 'CLOUD_MODE';
  private consecutiveMisses: number = 0;
  private lastHeartbeat: Date | null = null;
  private lastModeChange: Date;
  private startTime: Date;
  private transactionsProcessed: number = 0;
  private intervalId: NodeJS.Timeout | null = null;
  private clock: HLC;
  private syncManager: SyncManager;
  private pqcEngine: MLKEMEngine;
  private pendingTransactions: PendingTransaction[] = [];
  private isRunning: boolean = false;
  private connectedTerminals: Set<string> = new Set();
  
  // Commercial-Grade Components (Patent Claims 22-26)
  private commercialHeartbeat: CommercialMeshHeartbeat;

  constructor(config: Partial<HeartbeatConfig> = {}) {
    super();
    this.config = { ...DEFAULT_CONFIG, ...config };
    this.clock = getGlobalClock(this.config.nodeId);
    this.syncManager = getSyncManager(this.config.cloudApiUrl, this.config.nodeId);
    this.pqcEngine = getPQCEngine(this.config.nodeId);
    this.startTime = new Date();
    this.lastModeChange = new Date();
    
    // Initialize Commercial-Grade Components (Patent Claims 22-26)
    this.commercialHeartbeat = getCommercialHeartbeat(this.config.nodeId);
    
    // Register default terminals
    this.connectedTerminals.add('terminal-pos-001');
    this.connectedTerminals.add('terminal-atm-001');
    this.connectedTerminals.add('terminal-mobile-001');
  }

  /**
   * Starts the heartbeat monitor loop.
   * Step S502 in patent specification.
   */
  start(): void {
    if (this.isRunning) {
      heartbeatLogger.warn('Heartbeat monitor already running');
      return;
    }

    heartbeatLogger.info('Starting Heartbeat Monitor', {
      metadata: {
        nodeId: this.config.nodeId,
        intervalMs: this.config.heartbeatIntervalMs,
        missThreshold: this.config.missThreshold
      }
    });
    
    this.isRunning = true;
    this.intervalId = setInterval(() => this.checkHeartbeat(), this.config.heartbeatIntervalMs);
    this.emit('started', this.getStatus());
  }

  /**
   * Stops the heartbeat monitor.
   */
  stop(): void {
    if (this.intervalId) {
      clearInterval(this.intervalId);
      this.intervalId = null;
    }
    this.isRunning = false;
    heartbeatLogger.info('Heartbeat Monitor stopped');
    this.emit('stopped', this.getStatus());
  }

  /**
   * Step S504: Check if heartbeat is received.
   */
  private async checkHeartbeat(): Promise<void> {
    try {
      const received = await this.sendHeartbeat();

      if (received) {
        // Heartbeat received - reset counter
        this.consecutiveMisses = 0;
        this.lastHeartbeat = new Date();

        // If we were in Sovereign Mode, transition back to Cloud Mode
        if (this.mode === 'SOVEREIGN_MODE') {
          await this.transitionToCloudMode();
        }
      } else {
        // Heartbeat missed
        this.consecutiveMisses++;
        
        // Step S506: Check threshold
        if (this.consecutiveMisses >= this.config.missThreshold && this.mode === 'CLOUD_MODE') {
          await this.transitionToSovereignMode();
        }
      }
    } catch (error) {
      this.consecutiveMisses++;
      
      if (this.consecutiveMisses >= this.config.missThreshold && this.mode === 'CLOUD_MODE') {
        await this.transitionToSovereignMode();
      }
    }
  }

  /**
   * Sends heartbeat ping to cloud and waits for response.
   */
  private async sendHeartbeat(): Promise<boolean> {
    const controller = new AbortController();
    const timeoutId = setTimeout(() => controller.abort(), this.config.heartbeatTimeoutMs);

    try {
      const nonce = Date.now().toString(36) + Math.random().toString(36).substr(2);
      
      const response = await fetch(`${this.config.cloudApiUrl}/heartbeat`, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'X-Edge-Node-Id': this.config.nodeId,
          'X-Heartbeat-Nonce': nonce
        },
        body: JSON.stringify({ 
          nodeId: this.config.nodeId,
          nonce,
          timestamp: Date.now()
        }),
        signal: controller.signal
      });

      clearTimeout(timeoutId);
      return response.ok;
    } catch {
      clearTimeout(timeoutId);
      return false;
    }
  }

  /**
   * Step S508-S514: Transition to Sovereign Mode (activate Ghost Core).
   */
  private async transitionToSovereignMode(): Promise<void> {
    const startTransition = Date.now();
    
    heartbeatLogger.warn('PARTITION DETECTED - Initiating Sovereign Mode transition');
    this.mode = 'TRANSITIONING';
    this.emit('partitionDetected', { consecutiveMisses: this.consecutiveMisses });

    // S510: Activate HLC
    const hlcTimestamp = this.clock.now();
    heartbeatLogger.info('HLC Activated', { metadata: { hlc: HLC.toString(hlcTimestamp) } });

    // S512: PQC Handshake - Establish quantum-resistant sessions with all connected terminals
    heartbeatLogger.info('PQC Handshake initiated', { metadata: { algorithm: 'ML-KEM-768' } });
    const pqcSessions: Array<{ terminalId: string; sessionId: string }> = [];
    
    for (const terminalId of Array.from(this.connectedTerminals)) {
      try {
        // Generate mock terminal public key (1184 bytes for ML-KEM-768)
        const terminalPubKey = Buffer.alloc(1184);
        // In production, this would be received from the terminal
        
        const session = this.pqcEngine.establishSession(terminalId, terminalPubKey);
        pqcSessions.push({
          terminalId,
          sessionId: session.sessionId
        });
        heartbeatLogger.debug('PQC session established', {
          metadata: { terminalId, sessionIdPrefix: session.sessionId.substring(0, 8) }
        });
      } catch (error) {
        heartbeatLogger.error('Failed to establish PQC session', {
          metadata: { terminalId },
          error: error instanceof Error ? error : new Error(String(error))
        });
      }
    }
    
    heartbeatLogger.info('PQC Handshake complete', {
      metadata: {
        sessionsEstablished: pqcSessions.length,
        algorithm: 'ML-KEM-768 (NIST FIPS 203)',
        publicKeyBytes: 1184,
        sharedSecretBytes: 32
      }
    });

    // S514: Transition to Sovereign State
    this.mode = 'SOVEREIGN_MODE';
    this.lastModeChange = new Date();
    
    // Commercial-Grade: Trigger Ephemeral Vault key rotation on Sovereign Switch (Patent Claim 26)
    heartbeatLogger.info('Sovereign Switch triggered - rotating ephemeral keys');
    this.commercialHeartbeat.onSovereignSwitch();
    
    // Commercial-Grade: Analyze path health for self-healing (Patent Claim 23)
    const sentinel = this.commercialHeartbeat.getSentinel();
    const meshNodes = ['kampala-central', 'entebbe-airport', 'jinja-industrial', 'gulu-northern', 'mbarara-western', 'mbale-eastern'];
    for (const nodeId of meshNodes) {
      if (nodeId !== this.config.nodeId) {
        sentinel.analyzePathIntegrity(nodeId, hlcTimestamp);
      }
    }
    
    const transitionTime = Date.now() - startTransition;
    heartbeatLogger.warn('SOVEREIGN MODE ACTIVE', { metadata: { transitionMs: transitionTime } });
    
    this.emit('sovereignModeActivated', {
      transitionTimeMs: transitionTime,
      hlcTimestamp: hlcTimestamp.toString(),
      nodeId: this.config.nodeId,
      pqcSessions: pqcSessions.length,
      algorithm: 'ML-KEM-768',
      commercialGrade: {
        ephemeralKeyRotated: true,
        pathsAnalyzed: meshNodes.length - 1,
        sentinelActive: true
      }
    });
  }

  /**
   * Transition back to Cloud Mode with Delta-Sync reconciliation.
   */
  private async transitionToCloudMode(): Promise<void> {
    heartbeatLogger.info('CONNECTION RESTORED - Initiating Cloud Mode transition');
    this.mode = 'TRANSITIONING';
    this.emit('connectionRestored', { pendingTransactions: this.pendingTransactions.length });

    // Run Delta-Sync reconciliation
    if (this.pendingTransactions.length > 0) {
      heartbeatLogger.info('Reconciling pending transactions', {
        metadata: { count: this.pendingTransactions.length }
      });
      
      const syncResult = await this.syncManager.fullReconciliation(this.pendingTransactions);
      
      if (syncResult.success) {
        // Clear synced transactions
        this.pendingTransactions = this.pendingTransactions.filter(tx => !tx.synced);
        heartbeatLogger.info('Reconciliation complete', { metadata: { syncedCount: syncResult.syncedCount } });
      } else {
        heartbeatLogger.error('Reconciliation failed', { metadata: { errors: syncResult.errors } });
      }
      
      this.emit('reconciliationComplete', syncResult);
    }

    this.mode = 'CLOUD_MODE';
    this.lastModeChange = new Date();
    heartbeatLogger.info('CLOUD MODE ACTIVE');
    
    this.emit('cloudModeActivated', { timestamp: new Date() });
  }

  /**
   * Records a transaction (used during Sovereign Mode).
   * Step S516: Record to Local Ledger with PQC signature.
   */
  recordTransaction(tx: Omit<PendingTransaction, 'hlcTimestamp' | 'synced' | 'createdAt'>): PendingTransaction {
    const hlcTimestamp = this.clock.now();
    
    // Generate PQC signature if in Sovereign Mode
    let pqcSignature = tx.pqcSignature;
    if (this.mode === 'SOVEREIGN_MODE') {
      // Use the first available terminal session for signing
      const terminalId = Array.from(this.connectedTerminals)[0] || 'default-terminal';
      try {
        const txData = `${tx.id}:${tx.amount}:${tx.currency}:${hlcTimestamp}`;
        const sig = this.pqcEngine.signTransaction(terminalId, txData);
        pqcSignature = sig.signature.toString('hex');
        heartbeatLogger.debug('PQC signature generated', {
          metadata: { sigPrefix: pqcSignature.substring(0, 16), algorithm: 'HMAC-SHA256-PQC' }
        });
      } catch (error) {
        // Fall back to provided signature if no session available
        heartbeatLogger.debug('Using provided signature (no PQC session)');
      }
    }
    
    const fullTx: PendingTransaction = {
      ...tx,
      pqcSignature,
      hlcTimestamp,
      synced: false,
      createdAt: new Date()
    };

    this.pendingTransactions.push(fullTx);
    this.transactionsProcessed++;

    heartbeatLogger.info('Transaction recorded', {
      metadata: {
        mode: this.mode,
        transactionId: tx.id,
        amount: tx.amount,
        currency: tx.currency,
        hlc: HLC.toString(hlcTimestamp)
      }
    });

    this.emit('transactionRecorded', fullTx);
    return fullTx;
  }

  /**
   * Returns current system status.
   */
  getStatus(): HeartbeatStatus {
    return {
      mode: this.mode,
      consecutiveMisses: this.consecutiveMisses,
      lastHeartbeat: this.lastHeartbeat,
      lastModeChange: this.lastModeChange,
      uptimeSeconds: Math.floor((Date.now() - this.startTime.getTime()) / 1000),
      transactionsProcessed: this.transactionsProcessed,
      pendingSyncCount: this.pendingTransactions.filter(tx => !tx.synced).length
    };
  }

  /**
   * Returns current mode.
   */
  getMode(): SystemMode {
    return this.mode;
  }

  /**
   * Returns pending transactions (for sync status display).
   */
  getPendingTransactions(): PendingTransaction[] {
    return [...this.pendingTransactions];
  }

  /**
   * Returns the Commercial-Grade Heartbeat module.
   * Provides access to:
   * - Sentinel Self-Healing (Patent Claim 23)
   * - Lattice-Identity Manager (Patent Claim 24)
   * - Causal Sharding Manager (Patent Claim 25)
   * - Ephemeral Vault Manager (Patent Claim 26)
   * - Sovereign Isolation Manager (Patent Claim 22)
   */
  getCommercialHeartbeat(): CommercialMeshHeartbeat {
    return this.commercialHeartbeat;
  }

  /**
   * Force transition to Sovereign Mode (for testing/demo).
   */
  async forceSovereignMode(): Promise<void> {
    if (this.mode !== 'SOVEREIGN_MODE') {
      this.consecutiveMisses = this.config.missThreshold;
      await this.transitionToSovereignMode();
    }
  }

  /**
   * Force reconnection attempt (for testing/demo).
   */
  async forceReconnect(): Promise<void> {
    if (this.mode === 'SOVEREIGN_MODE') {
      await this.transitionToCloudMode();
    }
  }
}

// Export singleton instance
let heartbeatInstance: HeartbeatMonitor | null = null;

export function getHeartbeatMonitor(config?: Partial<HeartbeatConfig>): HeartbeatMonitor {
  if (!heartbeatInstance) {
    heartbeatInstance = new HeartbeatMonitor(config);
  }
  return heartbeatInstance;
}
