/**
 * Function/custom-example.js
 * ---------------------------------------------------------------------------
 * CUSTOM FUNCTION EXAMPLE - "Quick System Snapshot"
 *
 * A small but fully working module that demonstrates every part of the module
 * API: the descriptor fields, init(), the ctx helpers, the report builder,
 * logging, prompts and error handling.
 *
 * Copy Function/_TEMPLATE.js (not this file) when you start a new module -
 * this one is meant to be read as a worked example.
 * ---------------------------------------------------------------------------
 */

'use strict';

const os = require('os');
const path = require('path');

module.exports = {
  name: 'Quick System Snapshot (Example)',
  menuName: 'Quick System Snapshot  (example module)',
  description: 'Example module: shows live CPU / memory / disk / network status and can save it as a report.',
  version: '1.0.0',
  author: 'InfinitySniper HFX',
  category: 'Tools',
  order: 90,
  requiredPermissions: 'normal',
  destructive: false,
  dependencies: [],
  minimumAppVersion: '1.0.0',
  requiresAdmin: false,
  permissions: ['system:read', 'filesystem:write(reports)'],
  tags: ['example', 'template', 'snapshot'],

  config: {
    /** Save the snapshot automatically instead of asking. */
    autoSave: false,
    /** How many top processes to list (0 disables the process query). */
    topProcesses: 8,
  },

  help:
    'Demonstrates how a custom function is structured. It collects a quick health ' +
    'snapshot of the machine and can write it to the reports folder. Use it as a ' +
    'reference when writing your own modules.',

  /** Optional lifecycle hook - runs once at load time. */
  async init(ctx) {
    ctx.logger.debug('custom-example', 'Example module initialised');
  },

  async execute(ctx) {
    const { ui, prompt, system, report: reportLib, logger, paths, config } = ctx;

    ui.blank();
    ui.box({
      title: 'QUICK SYSTEM SNAPSHOT',
      lines: [
        ui.c.gray('Example module - a live snapshot of this machine.'),
        ui.c.gray('Source: Function/custom-example.js'),
      ],
      color: 'brightMagenta',
    });
    ui.blank();

    /* ---- live values from Node itself (no external dependency) --------- */
    const cpus = os.cpus();
    const totalMem = os.totalmem();
    const freeMem = os.freemem();
    const usedMem = totalMem - freeMem;
    const usedPercent = Math.round((usedMem / totalMem) * 100);
    const load = os.loadavg()[0];

    ui.section('LIVE STATUS');
    ui.blank();
    ui.field('Computer Name', os.hostname());
    ui.field('User', os.userInfo().username + (ctx.isAdmin ? ' (administrator)' : ''));
    ui.field('Platform', `${os.type()} ${os.release()} (${process.arch})`);
    ui.field('Uptime', system.formatDuration(os.uptime()));
    ui.field('CPU', cpus.length ? `${cpus[0].model.trim()}  x${cpus.length}` : 'Unknown');
    if (Number.isFinite(load) && load > 0) ui.field('Load Average (1m)', load.toFixed(2));
    ui.blank();

    ui.println('  ' + ui.c.gray(ui.padEnd('Memory Usage', 26)) + ui.c.gray(': ') + ui.progressBar(usedMem, totalMem, 24));
    ui.field(
      'Memory',
      `${system.formatBytes(usedMem)} used of ${system.formatBytes(totalMem)}  (${usedPercent}% - ${system.formatBytes(freeMem)} free)`
    );

    /* ---- an optional PowerShell query, with graceful failure ----------- */
    let processes = [];
    if (system.IS_WINDOWS && config.topProcesses > 0) {
      ui.blank();
      const spin = ui.spinner('Collecting the busiest processes...');
      // NOTE: the Select-Object pipeline must stay on ONE line - a line break
      // after "-First N" would end the statement and break the query.
      const query = [
        '$ErrorActionPreference = "SilentlyContinue"',
        '@(Get-Process | Sort-Object WorkingSet64 -Descending | ' +
          `Select-Object -First ${config.topProcesses} ` +
          '@{n="Name";e={$_.ProcessName}}, @{n="Memory";e={$_.WorkingSet64}}, Id) | ConvertTo-Json -Compress',
      ].join('\n');

      const result = await system.runPowerShellJson(query, { timeoutMs: 30000 });
      spin.stop();

      if (result.ok) {
        processes = system.asArray(result.data);
      } else {
        // A failing sub-query must never abort the module.
        ui.warning('The process list is unavailable on this system.');
        logger.warn('custom-example', 'Process query failed', result.stderr);
      }
    }

    if (processes.length) {
      ui.section('TOP PROCESSES BY MEMORY');
      ui.blank();
      ui.table(
        ['PROCESS', 'PID', 'MEMORY'],
        processes.map((p) => [
          ui.c.brightWhite(String(p.Name || '?')),
          ui.c.gray(String(p.Id || '?')),
          ui.c.brightCyan(system.formatBytes(p.Memory)),
        ]),
        { align: ['left', 'right', 'right'] }
      );
    }

    /* ---- disks --------------------------------------------------------- */
    let volumes = [];
    if (system.IS_WINDOWS) {
      const result = await system.runPowerShellJson(
        '@(Get-CimInstance Win32_LogicalDisk -Filter "DriveType = 3" | ' +
          'Select-Object DeviceID, Size, FreeSpace, VolumeName) | ConvertTo-Json -Compress',
        { timeoutMs: 30000 }
      );
      if (result.ok) volumes = system.asArray(result.data);
    }

    if (volumes.length) {
      ui.blank();
      ui.section('DRIVES');
      ui.blank();
      for (const volume of volumes) {
        const size = Number(volume.Size) || 0;
        const free = Number(volume.FreeSpace) || 0;
        const used = size - free;
        const label = `${volume.DeviceID} ${volume.VolumeName ? '(' + volume.VolumeName + ')' : ''}`.trim();
        ui.println('  ' + ui.c.brightWhite(ui.padEnd(label, 22)) + ui.progressBar(used, size, 22));
        ui.println(
          '  ' + ui.c.gray(ui.padEnd('', 22)) +
          ui.c.gray(`${system.formatBytes(free)} free of ${system.formatBytes(size)}`)
        );
      }
    }

    /* ---- network ------------------------------------------------------- */
    ui.blank();
    ui.section('NETWORK INTERFACES');
    ui.blank();
    const interfaces = os.networkInterfaces();
    let shown = 0;
    for (const [name, entries] of Object.entries(interfaces)) {
      for (const entry of entries || []) {
        if (entry.internal || entry.family !== 'IPv4') continue;
        ui.field(name, `${entry.address}  ${ui.c.gray('MAC ' + entry.mac)}`, 26);
        shown += 1;
      }
    }
    if (!shown) ui.println('  ' + ui.c.gray('No active IPv4 interface was found.'));

    /* ---- optional report ----------------------------------------------- */
    ui.blank();
    const shouldSave = config.autoSave || (await prompt.confirm('Save this snapshot as a report file?')) === true;

    if (shouldSave) {
      const snapshot = reportLib.createReport({
        title: 'QUICK SYSTEM SNAPSHOT',
        subtitle: 'Generated by the custom-example module',
      });

      const general = snapshot.section('GENERAL');
      general.add('Computer Name', os.hostname());
      general.add('User', os.userInfo().username);
      general.add('Platform', `${os.type()} ${os.release()} (${process.arch})`);
      general.add('Uptime', system.formatDuration(os.uptime()));
      general.add('CPU', cpus.length ? cpus[0].model.trim() : null);
      general.add('Logical Processors', String(cpus.length));

      const memory = snapshot.section('MEMORY');
      memory.add('Total', system.formatBytes(totalMem));
      memory.add('Used', `${system.formatBytes(usedMem)} (${usedPercent}%)`);
      memory.add('Free', system.formatBytes(freeMem));

      if (volumes.length) {
        const drives = snapshot.section('DRIVES');
        for (const volume of volumes) {
          const group = drives.group(`${volume.DeviceID} ${volume.VolumeName || ''}`.trim());
          group.add('Total', system.formatBytes(volume.Size));
          group.add('Free', system.formatBytes(volume.FreeSpace));
        }
      }

      if (processes.length) {
        const list = snapshot.section('TOP PROCESSES');
        processes.forEach((p, index) => {
          list.add(`${index + 1}. ${p.Name}`, `PID ${p.Id} - ${system.formatBytes(p.Memory)}`);
        });
      }

      const file = path.join(paths.reports, `${ctx.logger.fileStamp()}_SystemSnapshot.txt`);
      const saved = snapshot.save(file);

      if (saved.ok) {
        ui.ok('Snapshot saved.');
        ui.println('  ' + ui.c.gray('Location: ') + ui.c.brightCyan(file));
        logger.info('custom-example', 'Snapshot report saved', file);
      } else {
        ui.error(`The snapshot could not be saved: ${saved.error}`);
        logger.error('custom-example', 'Snapshot report could not be saved', saved.error);
      }
    }

    ui.blank();
    ui.completed('Snapshot finished.');
    return { ok: true, memoryUsedPercent: usedPercent };
  },
};
