#!/usr/bin/env node
/**
 * DStatus macOS Agent - Mac mini M2
 * 模拟 Go agent 上报格式: POST /stats/update, Header Key, Body {sid, data}
 */
const os = require('os');
const https = require('https');
const http = require('http');
const { execSync } = require('child_process');

const CONFIG = {
  server: 'http://51.81.222.43:5555',
  apiKey: 'macmini_report_key_2026',
  sid: '3b24c3cb-d06b-4747-83a8-a4c1ca11d4df',
  interval: 2,
  device: 'en0'
};

let prevRx = 0, prevTx = 0, prevTime = 0, firstRx = 0, firstTx = 0;

function getCpu() {
  try {
    const out = execSync("ps -A -o %cpu | awk '{s+=$1} END {print s/100}'", { encoding: 'utf8', timeout: 3000 });
    const v = parseFloat(out.trim()) || 0;
    return { multi: Math.min(v, 1), single: os.cpus().map(() => Math.min(v, 1)) };
  } catch { return { multi: 0, single: [0] }; }
}

function getDisk() {
  try {
    const out = execSync("df -k / | tail -1", { encoding: 'utf8', timeout: 3000 });
    const p = out.trim().split(/\s+/);
    const total = parseInt(p[1]) * 1024;
    const used = parseInt(p[2]) * 1024;
    const free = parseInt(p[3]) * 1024;
    const pct = parseFloat(p[4]) || 0;
    return {
      free, total, used,
      disks: [{ device: p[0], free, total, used, fstype: 'apfs', mount: '/', percent: pct }]
    };
  } catch { return { free: 0, total: 0, used: 0, disks: [] }; }
}

function getMem() {
  const total = os.totalmem();
  const free = os.freemem();
  const used = total - free;
  return {
    virtual: {
      total, available: free, used, usedPercent: (used / total) * 100,
      free, active: 0, inactive: 0, wired: 0, laundry: 0,
      buffers: 0, cached: 0, writeBack: 0, dirty: 0,
      writeBackTmp: 0, shared: 0, slab: 0, sreclaimable: 0,
      sunreclaim: 0, pageTables: 0, swapCached: 0,
      commitLimit: 0, committedAS: 0, highTotal: 0, highFree: 0,
      lowTotal: 0, lowFree: 0, swapTotal: 0, swapFree: 0,
      mapped: 0, vmallocTotal: 0, vmallocUsed: 0, vmallocChunk: 0,
      hugePagesTotal: 0, hugePagesFree: 0, hugePagesRsvd: 0,
      hugePagesSurp: 0, hugePageSize: 0, anonHugePages: 0
    },
    swap: { total: 0, used: 0, free: 0, usedPercent: 0, sin: 0, sout: 0, pgIn: 0, pgOut: 0, pgFault: 0, pgMajFault: 0 }
  };
}

function getNet() {
  try {
    const out = execSync(`netstat -ibI ${CONFIG.device} | awk 'NR==2{print $7,$10}'`, { encoding: 'utf8', timeout: 3000 });
    const [rx, tx] = out.trim().split(/\s+/).map(Number);
    const now = Date.now();
    if (!firstRx) { firstRx = rx; firstTx = tx; }
    const deltaIn = prevRx ? Math.max(0, (rx || 0) - prevRx) : 0;
    const deltaOut = prevTx ? Math.max(0, (tx || 0) - prevTx) : 0;
    prevRx = rx || 0; prevTx = tx || 0; prevTime = now;
    return {
      delta: { in: deltaIn, out: deltaOut },
      total: { in: (rx || 0) - firstRx, out: (tx || 0) - firstTx }
    };
  } catch { return { delta: { in: 0, out: 0 }, total: { in: 0, out: 0 } }; }
}

function getHost() {
  return {
    hostname: os.hostname(),
    uptime: Math.floor(os.uptime()),
    bootTime: Math.floor(Date.now() / 1000 - os.uptime()),
    procs: 0,
    os: 'darwin',
    platform: 'macOS',
    platformFamily: 'darwin',
    platformVersion: os.release(),
    kernelVersion: os.release(),
    kernelArch: os.arch() === 'arm64' ? 'aarch64' : os.arch(),
    virtualizationSystem: '',
    virtualizationRole: '',
    hostId: CONFIG.sid
  };
}

function collectData() {
  const cpu = getCpu();
  const disk = getDisk();
  const mem = getMem();
  const net = getNet();
  const host = getHost();
  return {
    cpu, disk: { free: disk.free, total: disk.total, used: disk.used },
    disks: disk.disks, host, hostname: os.hostname(),
    mem, net, timestamp: Date.now()
  };
}

function report() {
  const data = collectData();
  const body = JSON.stringify({ sid: CONFIG.sid, data });
  const mod = CONFIG.server.startsWith('https') ? https : http;
  const req = mod.request(`${CONFIG.server}/stats/update`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Content-Length': Buffer.byteLength(body),
      'Key': CONFIG.apiKey
    }
  }, res => {
    let d = '';
    res.on('data', c => d += c);
    res.on('end', () => {
      try {
        const r = JSON.parse(d);
        if (r.success || r.status === 1) console.log(`[${new Date().toLocaleTimeString()}] ✅ 上报成功`);
        else console.log(`[${new Date().toLocaleTimeString()}] ❌`, d.substring(0, 100));
      } catch { console.log(`[${new Date().toLocaleTimeString()}] ❌ 解析失败:`, d.substring(0, 100)); }
    });
  });
  req.on('error', e => console.error('上报错误:', e.message));
  req.write(body);
  req.end();
}

console.log('DStatus macOS Agent | SID:', CONFIG.sid);
report();
setInterval(report, CONFIG.interval * 1000);
