import machineIdPkg from 'node-machine-id';
import si from 'systeminformation';
import { createHash } from 'crypto';
import { EventEmitter } from 'events';

const { machineId } = machineIdPkg;

/**
 * Device Fingerprinting System for License Management
 * Creates unique device identifiers for license enforcement
 */
export class DeviceFingerprint extends EventEmitter {
  constructor() {
    super();
    this.deviceInfo = null;
    this.fingerprint = null;
    console.log('🔍 Device Fingerprint system initialized');
  }

  /**
   * Generate comprehensive device fingerprint
   */
  async generateFingerprint() {
    try {
      console.log('🔍 Generating device fingerprint...');
      
      // Get machine ID (most reliable)
      const machineIdValue = await machineId();
      
      // Get system information
      const [cpu, system, osInfo, memory, networkInterfaces] = await Promise.all([
        si.cpu(),
        si.system(),
        si.osInfo(),
        si.mem(),
        si.networkInterfaces()
      ]);

      // Create device info object
      this.deviceInfo = {
        machineId: machineIdValue,
        cpu: {
          manufacturer: cpu.manufacturer,
          brand: cpu.brand,
          family: cpu.family,
          model: cpu.model,
          cores: cpu.cores,
          physicalCores: cpu.physicalCores
        },
        system: {
          manufacturer: system.manufacturer,
          model: system.model,
          version: system.version,
          serial: system.serial,
          uuid: system.uuid
        },
        os: {
          platform: osInfo.platform,
          distro: osInfo.distro,
          release: osInfo.release,
          arch: osInfo.arch,
          hostname: osInfo.hostname
        },
        memory: {
          total: Math.round(memory.total / (1024 * 1024 * 1024)) // GB
        },
        network: networkInterfaces
          .filter(iface => !iface.internal && iface.mac)
          .map(iface => ({
            iface: iface.iface,
            mac: iface.mac,
            type: iface.type
          }))
      };

      // Generate multiple fingerprint levels
      const hardwareFingerprint = this.generateHardwareFingerprint();
      const systemFingerprint = this.generateSystemFingerprint();

      this.fingerprint = {
        // Level 1: Hardware-based (most stable)
        hardware: hardwareFingerprint,

        // Level 2: System-based (moderately stable)
        system: systemFingerprint,

        // Level 3: Combined (most unique)
        combined: this.generateCombinedFingerprint(hardwareFingerprint, systemFingerprint),

        // Metadata
        generated: new Date().toISOString(),
        version: '1.0'
      };

      console.log('✅ Device fingerprint generated successfully');
      console.log(`🔍 Hardware ID: ${this.fingerprint.hardware.substring(0, 16)}...`);
      
      this.emit('fingerprintGenerated', this.fingerprint);
      
      return this.fingerprint;
    } catch (error) {
      console.error('❌ Failed to generate device fingerprint:', error.message);
      throw error;
    }
  }

  /**
   * Generate hardware-based fingerprint (most stable)
   */
  generateHardwareFingerprint() {
    const hardwareData = [
      this.deviceInfo.machineId,
      this.deviceInfo.cpu.manufacturer,
      this.deviceInfo.cpu.brand,
      this.deviceInfo.cpu.family,
      this.deviceInfo.cpu.model,
      this.deviceInfo.cpu.cores,
      this.deviceInfo.system.manufacturer,
      this.deviceInfo.system.model,
      this.deviceInfo.system.uuid,
      this.deviceInfo.memory.total
    ].filter(Boolean).join('|');

    return createHash('sha256').update(hardwareData).digest('hex');
  }

  /**
   * Generate system-based fingerprint
   */
  generateSystemFingerprint() {
    const systemData = [
      this.deviceInfo.os.platform,
      this.deviceInfo.os.distro,
      this.deviceInfo.os.arch,
      this.deviceInfo.os.hostname,
      this.deviceInfo.system.serial,
      ...this.deviceInfo.network.map(n => n.mac)
    ].filter(Boolean).join('|');

    return createHash('sha256').update(systemData).digest('hex');
  }

  /**
   * Generate combined fingerprint (most unique)
   */
  generateCombinedFingerprint(hardwareFingerprint, systemFingerprint) {
    const combinedData = [
      hardwareFingerprint,
      systemFingerprint
    ].join('|');

    return createHash('sha256').update(combinedData).digest('hex');
  }

  /**
   * Validate device against stored fingerprint
   */
  async validateDevice(storedFingerprint) {
    try {
      if (!this.fingerprint) {
        await this.generateFingerprint();
      }

      const validation = {
        isValid: false,
        confidence: 0,
        matches: {
          hardware: false,
          system: false,
          combined: false
        },
        details: {}
      };

      // Check hardware fingerprint (highest priority)
      validation.matches.hardware = this.fingerprint.hardware === storedFingerprint.hardware;
      
      // Check system fingerprint
      validation.matches.system = this.fingerprint.system === storedFingerprint.system;
      
      // Check combined fingerprint
      validation.matches.combined = this.fingerprint.combined === storedFingerprint.combined;

      // 🔐 SECURITY HARDENING: Strengthen device validation
      let confidence = 0;
      if (validation.matches.hardware) confidence += 50; // Hardware is important
      if (validation.matches.system) confidence += 35;   // System is critical
      if (validation.matches.combined) confidence += 15; // Combined is verification

      validation.confidence = confidence;
      validation.isValid = confidence >= 85; // 🔐 SECURITY: Require higher confidence (85% vs 60%)

      // Detailed analysis
      validation.details = {
        machineIdMatch: this.deviceInfo.machineId === storedFingerprint.machineId,
        cpuMatch: this.compareCPU(storedFingerprint),
        systemMatch: this.compareSystem(storedFingerprint),
        networkMatch: this.compareNetwork(storedFingerprint)
      };

      console.log(`🔍 Device validation: ${validation.isValid ? 'VALID' : 'INVALID'} (${validation.confidence}% confidence)`);
      
      this.emit('deviceValidated', validation);
      
      return validation;
    } catch (error) {
      console.error('❌ Device validation failed:', error.message);
      throw error;
    }
  }

  /**
   * Compare CPU information
   */
  compareCPU(storedFingerprint) {
    if (!storedFingerprint.deviceInfo?.cpu) return false;
    
    const current = this.deviceInfo.cpu;
    const stored = storedFingerprint.deviceInfo.cpu;
    
    return (
      current.manufacturer === stored.manufacturer &&
      current.brand === stored.brand &&
      current.family === stored.family &&
      current.model === stored.model &&
      current.cores === stored.cores
    );
  }

  /**
   * Compare system information
   */
  compareSystem(storedFingerprint) {
    if (!storedFingerprint.deviceInfo?.system) return false;
    
    const current = this.deviceInfo.system;
    const stored = storedFingerprint.deviceInfo.system;
    
    return (
      current.manufacturer === stored.manufacturer &&
      current.model === stored.model &&
      current.uuid === stored.uuid
    );
  }

  /**
   * Compare network interfaces
   */
  compareNetwork(storedFingerprint) {
    if (!storedFingerprint.deviceInfo?.network) return false;
    
    const currentMacs = this.deviceInfo.network.map(n => n.mac).sort();
    const storedMacs = storedFingerprint.deviceInfo.network.map(n => n.mac).sort();
    
    // Check if at least one MAC address matches
    return currentMacs.some(mac => storedMacs.includes(mac));
  }

  /**
   * Get device summary for display
   */
  getDeviceSummary() {
    if (!this.deviceInfo) {
      return 'Device information not available';
    }

    return {
      name: `${this.deviceInfo.system.manufacturer} ${this.deviceInfo.system.model}`.trim() || 'Unknown Device',
      cpu: `${this.deviceInfo.cpu.brand} (${this.deviceInfo.cpu.cores} cores)`,
      os: `${this.deviceInfo.os.distro} ${this.deviceInfo.os.release}`,
      memory: `${this.deviceInfo.memory.total}GB RAM`,
      network: this.deviceInfo.network.length > 0 ? 
        `${this.deviceInfo.network.length} network interface(s)` : 
        'No network interfaces',
      fingerprint: this.fingerprint?.hardware?.substring(0, 16) + '...' || 'Not generated'
    };
  }

  /**
   * Export fingerprint for storage
   */
  exportFingerprint() {
    return {
      ...this.fingerprint,
      deviceInfo: this.deviceInfo,
      exported: new Date().toISOString()
    };
  }

  /**
   * Import fingerprint for validation
   */
  importFingerprint(fingerprintData) {
    this.fingerprint = fingerprintData;
    this.deviceInfo = fingerprintData.deviceInfo;
    
    console.log('📥 Device fingerprint imported');
    this.emit('fingerprintImported', fingerprintData);
  }

  /**
   * Check if device has changed significantly
   */
  async detectHardwareChanges(storedFingerprint) {
    try {
      await this.generateFingerprint();
      
      const changes = {
        hasChanges: false,
        changes: [],
        severity: 'none' // none, minor, major, critical
      };

      if (!storedFingerprint.deviceInfo) {
        changes.hasChanges = true;
        changes.severity = 'critical';
        changes.changes.push('No stored device information');
        return changes;
      }

      // Check for hardware changes
      if (!this.compareCPU(storedFingerprint)) {
        changes.hasChanges = true;
        changes.changes.push('CPU changed');
        changes.severity = 'major';
      }

      if (!this.compareSystem(storedFingerprint)) {
        changes.hasChanges = true;
        changes.changes.push('System hardware changed');
        changes.severity = 'major';
      }

      if (!this.compareNetwork(storedFingerprint)) {
        changes.hasChanges = true;
        changes.changes.push('Network interfaces changed');
        changes.severity = changes.severity === 'major' ? 'major' : 'minor';
      }

      // Check OS changes
      if (this.deviceInfo.os.platform !== storedFingerprint.deviceInfo.os.platform) {
        changes.hasChanges = true;
        changes.changes.push('Operating system platform changed');
        changes.severity = 'minor';
      }

      console.log(`🔍 Hardware change detection: ${changes.hasChanges ? changes.severity.toUpperCase() : 'NO CHANGES'}`);
      
      return changes;
    } catch (error) {
      console.error('❌ Hardware change detection failed:', error.message);
      throw error;
    }
  }
}
