/**
 * Function/_TEMPLATE.js
 * ===========================================================================
 *  INFINITYSNIPER HFX - FUNCTION TEMPLATE
 *  Copy this file to create a new function.
 * ===========================================================================
 *
 *  HOW TO ADD A FUNCTION
 *  -------------------------------------------------------------------------
 *  1. Copy this file into the category folder it belongs to:
 *
 *       Function/System/        hardware, CPU, GPU, RAM, monitoring
 *       Function/Storage/       disks, files, folders
 *       Function/Network/       adapters, ping, DNS, ports, scanning
 *       Function/Maintenance/   cleaning and upkeep
 *       Function/Diagnostics/   health, logs, crashes, security
 *       Function/Windows/       software, services, drivers, devices
 *       Function/Tools/         file tools and your own utilities
 *       Function/Reports/       exports and history views
 *
 *     e.g.  Function/Tools/my-function.js
 *
 *  2. Fill in the descriptor below and write your logic in execute(ctx).
 *  3. Start the application - the function appears in that category with its
 *     own number. No menu code is ever edited.
 *
 *  Files whose name starts with "_" or "." are ignored by the loader, which is
 *  why this template never shows up in the menu. Files ending in ".disabled.js"
 *  are ignored too - handy to park a module temporarily.
 *
 *  -------------------------------------------------------------------------
 *  THE ctx OBJECT PASSED TO execute()
 *  -------------------------------------------------------------------------
 *  ctx.ui          Rendering: box, menu, section, field, table, status,
 *                  spinner, progressBar, statusBar, c (colors), truncate, wrap
 *  ctx.prompt      NUMERIC input: select, confirm, choose, number, text, pause
 *  ctx.kit         Helpers: header, query, table, kv, offerExport, report, done
 *  ctx.logger      info / warn / error / exception / createOperationLog
 *  ctx.system      PowerShell + formatting + isAdmin + clean/asArray/firstOf
 *  ctx.report      createReport() - build a report, print it, save it
 *  ctx.paths       root, functions, logs, reports, backups, temp, config
 *  ctx.settings    Live settings (config/settings.json)
 *  ctx.configApi   get / set / save / reset for settings
 *  ctx.config      This module's own config block (defaults below)
 *  ctx.module      This module's descriptor (id, name, version, file, ...)
 *  ctx.modules     Every loaded module
 *  ctx.isAdmin     true when the application runs elevated
 *  ctx.safeMode    true when Safe Mode blocks destructive actions
 *  ctx.dryRun      true when the user asked for a no-changes run
 *  ctx.appVersion  Version of the framework
 *
 *  -------------------------------------------------------------------------
 *  RULES
 *  -------------------------------------------------------------------------
 *  - Numbers only. Never ask for letters; 0 always means Back / Cancel.
 *  - Print through ctx.ui, never console.log.
 *  - Anything that changes the system: set destructive: true, honour
 *    ctx.safeMode and ctx.dryRun, scan first, and confirm numerically.
 *  - Throwing is safe: the main menu catches it, shows an Error ID and
 *    returns the user to the menu.
 * ===========================================================================
 */

'use strict';

const path = require('path');
const kit = require('../../core/kit');
const system = require('../../core/system');

/* --------------------------------------------------------------------------
 * Data collection - read-only and fault tolerant
 * ------------------------------------------------------------------------ */

/**
 * Keep a PowerShell pipeline on ONE line: a line break ends the statement and
 * the query silently returns nothing.
 */
const QUERY = [
  '$ErrorActionPreference = "SilentlyContinue"',
  '@(Get-CimInstance Win32_OperatingSystem | Select-Object Caption, Version, BuildNumber) | ConvertTo-Json -Depth 3 -Compress',
].join('\n');

async function collect() {
  const result = await system.runPowerShellJson(QUERY, { timeoutMs: 30000 });
  return result.ok ? system.asArray(result.data) : null;
}

/* --------------------------------------------------------------------------
 * Module
 * ------------------------------------------------------------------------ */

module.exports = {
  /* ---- identity (name is required) ------------------------------------- */
  name: 'My Function',
  menuName: 'My Function',
  description: 'One line shown in the category menu and the Function Manager.',
  documentation:
    'Longer help text shown in the module details screen: what it reads, what it ' +
    'changes, and what needs administrator rights.',
  version: '1.0.0',
  author: 'Your Name',

  /* ---- placement -------------------------------------------------------- */
  /** Overrides the folder. Leave it out and the folder name decides. */
  category: 'Tools',
  /** Sort weight inside the category - lower numbers come first. */
  order: 100,
  /** Keywords used by Search Functions [17]. */
  tags: ['example', 'template'],
  /** Set to false to keep it loaded but greyed out; hidden hides it entirely. */
  enabled: true,
  hidden: false,

  /* ---- requirements ----------------------------------------------------- */
  /** 'normal' or 'administrator' - shown before the function runs. */
  requiredPermissions: 'normal',
  /** Readable capability list shown in the module details screen. */
  permissions: ['system:read'],
  /** true = changes the system: blocked by Safe Mode, must honour Dry Run. */
  destructive: false,
  /** npm packages this module needs; missing ones disable it with a message. */
  dependencies: [],
  /** The framework refuses politely instead of crashing if it is too old. */
  minimumAppVersion: '1.0.0',

  /* ---- defaults, delivered as ctx.config -------------------------------- */
  config: {
    maxRows: 25,
  },

  /* ---- lifecycle -------------------------------------------------------- */

  /** Optional. Runs once at load. Fast, silent, never prompts. */
  async init(ctx) {
    ctx.logger.debug(ctx.module.id, 'initialised');
  },

  /** Optional. Read-only probe used by System Health and the self-test run. */
  async selfTest(ctx) {
    if (!ctx.system.IS_WINDOWS) return { ok: false, message: 'Windows only' };
    const rows = await collect();
    return rows && rows.length
      ? { ok: true, message: 'data source responded' }
      : { ok: false, message: 'no data returned' };
  },

  /**
   * Optional. Contributes a section to the Export Center [8] -> Export Center.
   */
  reportProvider: {
    id: 'my-function',
    label: 'My Function',
    order: 200,
    async build(report) {
      const rows = await collect();
      const section = report.section('MY FUNCTION');
      if (!rows) {
        section.note('Not available during export.');
        return;
      }
      for (const row of rows) section.add('Caption', system.clean(row.Caption));
    },
  },

  /** REQUIRED. Runs when the user picks this function. */
  async execute(ctx) {
    const { ui, prompt, config } = ctx;

    kit.header('My Function', ['What this function does.', 'Read-only.']);
    if (!kit.requireWindows('This function')) return { ok: false, reason: 'unsupported-platform' };

    // ---- collect --------------------------------------------------------
    const spin = ui.spinner('Collecting information...');
    const rows = await collect();
    spin.stop();

    if (!rows || !rows.length) return kit.noData('information');

    // ---- display --------------------------------------------------------
    ui.section('RESULT');
    ui.blank();
    for (const row of rows.slice(0, config.maxRows)) {
      kit.kv('Caption', system.clean(row.Caption));
      kit.kv('Version', system.clean(row.Version));
      kit.kv('Build', system.clean(row.BuildNumber));
    }

    // ---- a numeric sub-menu (delete this block if you do not need one) ---
    for (;;) {
      ui.blank();
      ui.menu(
        [
          { key: '1', label: 'Refresh' },
          { key: '2', label: 'Export as a TXT report' },
          { separator: true },
          { key: '0', label: 'Back', color: 'gray' },
        ],
        { title: 'MY FUNCTION' }
      );
      ui.blank();

      const answer = await prompt.select();
      // End of piped input: leave instead of looping forever.
      if (!answer && prompt.isClosed()) break;
      if (answer === '0') break;

      if (answer === '1') {
        ui.clear();
        continue;
      }

      if (answer === '2') {
        const report = kit.report('My Function Report');
        const section = report.section('RESULT');
        for (const row of rows) {
          const group = section.group(String(system.clean(row.Caption) || 'Item'));
          group.add('Version', system.clean(row.Version));
          group.add('Build', system.clean(row.BuildNumber));
        }
        // Writes reports/<time>_<date>_MyFunction.txt
        kit.saveReport(report, 'MyFunction');
        await prompt.pause();
        continue;
      }

      ui.warning('Enter one of the numbers shown above, or 0 to go back.');
      await prompt.pause();
    }

    return kit.done('Finished.');
  },
};
