/**
 * ╔══════════════════════════════════════════════════════╗
 * ║  LICENSE KEY GENERATOR — VENDOR TOOL ONLY           ║
 * ║  DO NOT SHIP THIS FILE TO CLIENTS                   ║
 * ╚══════════════════════════════════════════════════════╝
 *
 * Usage:
 *   npx tsx scripts/generate-license.ts \
 *     --customer "ABC Company" \
 *     --customerId "cust-001" \
 *     --edition local \
 *     --users 10 \
 *     --expiry 365 \
 *     [--machine]   ← auto-detect current machine fingerprint
 *
 * For cloud edition, omit --machine.
 * For local edition, run on the TARGET machine or pass --machineHash manually.
 */

import * as crypto from 'crypto';
import * as path from 'path';
import * as fs from 'fs';
import * as os from 'os';
import type { LicensePayload } from '../lib/license/types';

// ─── Private Key (KEEP SECRET — never share or distribute) ───────────────────
// Store this in a separate secure file or env var in production.
// For development convenience, it's embedded here.
const PRIVATE_KEY = `-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgLcY4aZC9OtzHEaYY
Mu4S0qEnfW+cDhhFbKoeJQtLO52hRANCAAThW916sXi0XeBRX1bHFYHxjBhm9Ias
YHcPR9erY+VrFCqf6POn8LM0kjFJUDoc7OgB4oxIFCdJ3q054D6rZV4i
-----END PRIVATE KEY-----`;

// ─── Helpers ─────────────────────────────────────────────────────────────────

function parseArgs(): Record<string, string | boolean> {
  const args: Record<string, string | boolean> = {};
  const argv = process.argv.slice(2);
  for (let i = 0; i < argv.length; i++) {
    const arg = argv[i];
    if (arg.startsWith('--')) {
      const key = arg.slice(2);
      const next = argv[i + 1];
      if (next && !next.startsWith('--')) {
        args[key] = next;
        i++;
      } else {
        args[key] = true;
      }
    }
  }
  return args;
}

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 getMachineFingerprint(): string {
  const components = {
    hostname: crypto.createHash('sha256').update(os.hostname().toLowerCase()).digest('hex'),
    mac: crypto.createHash('sha256').update(getFirstNonLoopbackMac()).digest('hex'),
    platform: crypto.createHash('sha256').update(`${os.platform()}-${os.arch()}`).digest('hex'),
  };
  return JSON.stringify(components);
}

function generateLicenseKey(payload: LicensePayload): string {
  const payloadJson = JSON.stringify(payload);
  const payloadB64 = Buffer.from(payloadJson).toString('base64url');

  const signer = crypto.createSign('SHA256');
  signer.update(payloadB64);
  const signature = signer.sign(PRIVATE_KEY);
  const sigB64 = signature.toString('base64url');

  return `${payloadB64}.${sigB64}`;
}

// ─── Main ─────────────────────────────────────────────────────────────────────

const args = parseArgs();

const customer = String(args['customer'] ?? '');
const customerId = String(args['customerId'] ?? `cust-${Date.now()}`);
const edition = (args['edition'] as 'local' | 'cloud') ?? 'local';
const maxUsers = parseInt(String(args['users'] ?? '5'), 10);
const expiryDays = parseInt(String(args['expiry'] ?? '365'), 10);
const useMachine = args['machine'] === true;
const machineHashOverride = args['machineHash'] ? String(args['machineHash']) : null;
const tenantId = args['tenantId'] ? String(args['tenantId']) : null;

if (!customer) {
  console.error('Error: --customer is required');
  process.exit(1);
}

const issuedAt = new Date();
const expiresAt = new Date(issuedAt.getTime() + expiryDays * 24 * 60 * 60 * 1000);

let machineHash: string | null = null;
if (edition === 'local') {
  if (machineHashOverride) {
    machineHash = machineHashOverride;
  } else if (useMachine) {
    machineHash = getMachineFingerprint();
    console.log('\nMachine fingerprint (current machine):');
    console.log(machineHash);
  } else {
    console.warn('Warning: Local edition without --machine flag. License will not be machine-bound.');
    console.warn('Use --machine to bind to this machine, or --machineHash <hash> for a specific machine.');
  }
}

const payload: LicensePayload = {
  licenseId: crypto.randomUUID(),
  customerId,
  customerName: customer,
  edition,
  maxUsers,
  features: ['core', 'invoicing', 'purchasing', 'inventory'],
  issuedAt: issuedAt.toISOString(),
  expiresAt: expiresAt.toISOString(),
  machineHash,
  tenantId: edition === 'cloud' ? (tenantId ?? `tenant-${customerId}`) : null,
};

const licenseKey = generateLicenseKey(payload);

console.log('\n╔═══════════════════════════════════════════════════╗');
console.log('║           LICENSE KEY GENERATED                   ║');
console.log('╚═══════════════════════════════════════════════════╝');
console.log('\nCustomer:  ', customer);
console.log('CustomerID:', customerId);
console.log('Edition:   ', edition);
console.log('Max Users: ', maxUsers);
console.log('Issued:    ', issuedAt.toLocaleDateString());
console.log('Expires:   ', expiresAt.toLocaleDateString(), `(${expiryDays} days)`);
console.log('Machine:   ', machineHash ? 'Bound' : 'Not bound');
console.log('\n─── LICENSE KEY ─────────────────────────────────────\n');
console.log(licenseKey);
console.log('\n─────────────────────────────────────────────────────\n');

// Save to file
const outputFile = path.join(process.cwd(), `license-${customerId}-${Date.now()}.txt`);
fs.writeFileSync(outputFile, [
  `Customer: ${customer}`,
  `CustomerID: ${customerId}`,
  `Edition: ${edition}`,
  `Expires: ${expiresAt.toISOString()}`,
  ``,
  licenseKey,
].join('\n'), 'utf-8');

console.log(`Saved to: ${outputFile}`);
