import * as os from 'os';
import * as crypto from 'crypto';

interface MachineComponents {
  hostname: string;
  mac: string;
  platform: string;
}

function getFirstNonLoopbackMac(): string {
  const interfaces = os.networkInterfaces();
  for (const iface of Object.values(interfaces)) {
    if (!iface) continue;
    for (const addr of iface) {
      if (!addr.internal && addr.mac && addr.mac !== '00:00:00:00:00:00') {
        return addr.mac.toLowerCase();
      }
    }
  }
  return 'unknown-mac';
}

function getMachineComponents(): MachineComponents {
  return {
    hostname: os.hostname().toLowerCase(),
    mac: getFirstNonLoopbackMac(),
    platform: `${os.platform()}-${os.arch()}`,
  };
}

/** Returns a SHA-256 hash of all three machine components */
export function getMachineHash(): string {
  const { hostname, mac, platform } = getMachineComponents();
  const data = `${hostname}|${mac}|${platform}`;
  return crypto.createHash('sha256').update(data).digest('hex');
}

/**
 * Returns individual component hashes for 2-of-3 tolerance matching.
 * Allows one hardware component to change (e.g. NIC replacement).
 */
export function getMachineComponentHashes(): { hostname: string; mac: string; platform: string } {
  const components = getMachineComponents();
  return {
    hostname: crypto.createHash('sha256').update(components.hostname).digest('hex'),
    mac: crypto.createHash('sha256').update(components.mac).digest('hex'),
    platform: crypto.createHash('sha256').update(components.platform).digest('hex'),
  };
}

/**
 * Checks if a stored machineHash matches the current machine.
 * The stored hash can be:
 *  - A full combined hash (exact match)
 *  - A JSON string of { hostname, mac, platform } component hashes (2-of-3)
 */
export function matchesMachine(storedHash: string): boolean {
  // Try exact combined hash match first
  const currentHash = getMachineHash();
  if (storedHash === currentHash) return true;

  // Try 2-of-3 component hash tolerance
  try {
    const stored = JSON.parse(storedHash) as { hostname: string; mac: string; platform: string };
    const current = getMachineComponentHashes();
    let matches = 0;
    if (stored.hostname === current.hostname) matches++;
    if (stored.mac === current.mac) matches++;
    if (stored.platform === current.platform) matches++;
    return matches >= 2;
  } catch {
    // Not JSON, already tried exact match above
    return false;
  }
}

/** Returns a machine fingerprint string suitable for embedding in a license */
export function getMachineFingerprint(): string {
  return JSON.stringify(getMachineComponentHashes());
}
