'use strict';
/**
 * DeployPro License Check Middleware
 * Validates the installation's license against the centralised License Server.
 * Reads key from data/license.json; caches result for 6 hours; allows a
 * 24-hour grace period when the License Server is unreachable.
 */

const http  = require('http');
const https = require('https');
const path  = require('path');
const fs    = require('fs');
const os    = require('os');
const crypto = require('crypto');

const LICENSE_FILE   = path.join(__dirname, '..', 'data', 'license.json');
const CACHE_TTL_MS   = 6  * 60 * 60 * 1000;  // 6 hours
const GRACE_MS       = 24 * 60 * 60 * 1000;   // 24-hour grace if server unreachable
const LICENSE_SERVER = process.env.LICENSE_SERVER_URL || 'http://localhost:3000';

let _cache     = null;   // last validated status object
let _cacheTime = 0;      // epoch ms of last successful remote validation

// Stable machine fingerprint (hostname + CPU model hashed)
function getMachineId() {
  const raw = os.hostname() + os.cpus()[0].model + os.platform();
  return crypto.createHash('sha256').update(raw).digest('hex').slice(0, 32);
}

function readLicenseFile() {
  try {
    if (!fs.existsSync(LICENSE_FILE)) return null;
    return JSON.parse(fs.readFileSync(LICENSE_FILE, 'utf8'));
  } catch { return null; }
}

function saveLicenseFile(updates) {
  try {
    fs.mkdirSync(path.dirname(LICENSE_FILE), { recursive: true });
    const current = readLicenseFile() || {};
    fs.writeFileSync(LICENSE_FILE, JSON.stringify({ ...current, ...updates }, null, 2));
  } catch {}
}

function callRemote(key) {
  return new Promise(resolve => {
    const body = JSON.stringify({ key, machineId: getMachineId() });
    const u    = new URL('/api/license/validate', LICENSE_SERVER);
    const lib  = u.protocol === 'https:' ? https : http;

    const req = lib.request({
      hostname: u.hostname,
      port:     u.port || (u.protocol === 'https:' ? 443 : 80),
      path:     u.pathname,
      method:   'POST',
      headers:  { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(body) },
    }, res => {
      let raw = '';
      res.on('data', c => raw += c);
      res.on('end',  () => { try { resolve(JSON.parse(raw)); } catch { resolve(null); } });
    });

    req.on('error', () => resolve(null));
    req.setTimeout(5000, () => { req.destroy(); resolve(null); });
    req.write(body);
    req.end();
  });
}

/**
 * checkLicense() — resolves with a status object:
 *   { valid, mode, plan, planName, daysLeft, expiresAt, isTrial, isExpiringSoon, offline }
 */
async function checkLicense() {
  const lic = readLicenseFile();

  if (!lic || !lic.key) {
    _cache = { valid: false, mode: 'unlicensed',
               message: 'No license key. Visit /activate to register your copy.' };
    return _cache;
  }

  // Return cache if fresh enough
  if (_cache && _cache.valid && Date.now() - _cacheTime < CACHE_TTL_MS) {
    return _cache;
  }

  const result = await callRemote(lic.key);

  if (result && result.valid) {
    _cache = {
      valid:          true,
      mode:           result.plan,
      plan:           result.planName,
      expiresAt:      result.expiresAt,
      daysLeft:       result.daysLeft,
      maxSites:       result.maxSites,
      maxUsers:       result.maxUsers,
      isTrial:        result.plan === 'trial',
      isExpiringSoon: result.daysLeft <= 7,
      offline:        false,
    };
    _cacheTime = Date.now();
    saveLicenseFile({ lastValidated: new Date().toISOString(), licenseStatus: _cache });

  } else if (result === null) {
    // Server unreachable — check grace period
    const lastOk  = lic.lastValidated ? new Date(lic.lastValidated).getTime() : 0;
    const inGrace = Date.now() - lastOk < GRACE_MS;

    if (inGrace && lic.licenseStatus) {
      _cache = { ...lic.licenseStatus, offline: true,
                 message: 'License server unreachable — offline grace period active.' };
    } else {
      _cache = { valid: false, mode: 'offline',
                 message: 'License server unreachable and grace period expired. Contact support.' };
    }
  } else {
    _cache = { valid: false, mode: 'invalid', message: result.error || 'License validation failed.' };
    saveLicenseFile({ licenseStatus: _cache });
  }

  return _cache;
}

/** Quick synchronous getter for already-cached status */
function getStatus() { return _cache; }

/** Express middleware — attaches req.licenseStatus, never blocks requests */
function licenseMiddleware(req, res, next) {
  req.licenseStatus = _cache || { valid: false, mode: 'unknown' };
  next();
}

// ── Startup validation ───────────────────────────────────────────────────────
checkLicense()
  .then(s => {
    if (s.valid) {
      const tag = s.offline ? ' [OFFLINE MODE]' : '';
      console.log(`  License: ${s.plan || s.mode} — ${s.daysLeft ?? '?'} days left${tag}`);
      if (s.isExpiringSoon) console.warn(`  WARNING: License expires in ${s.daysLeft} day(s)!`);
    } else {
      console.warn(`  License: ${s.message || s.mode}`);
    }
  })
  .catch(() => {});

// Re-validate every 6 hours
setInterval(() => { checkLicense().catch(() => {}); }, CACHE_TTL_MS);

module.exports = { checkLicense, getStatus, licenseMiddleware };
