/**
 * Function/Diagnostics/restore-info.js
 * ---------------------------------------------------------------------------
 * SYSTEM RESTORE INFORMATION
 *
 * Whether System Protection is enabled, how much space is reserved and which
 * restore points exist. Creating a restore point is offered as an explicit,
 * confirmed action - nothing is created or deleted automatically.
 * ---------------------------------------------------------------------------
 */

'use strict';

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

/** RestorePointType values from the SystemRestore provider. */
const POINT_TYPES = {
  0: 'Application install',
  1: 'Application uninstall',
  10: 'Device driver install',
  12: 'Modify settings',
  13: 'Cancelled operation',
  7: 'Checkpoint',
};

const QUERY = [
  '$ErrorActionPreference = "SilentlyContinue"',
  '[ordered]@{',
  '  points = @(Get-CimInstance -Namespace root\\default -ClassName SystemRestore | Select-Object SequenceNumber, Description, CreationTime, RestorePointType, EventType);',
  '  shadow = @(Get-CimInstance Win32_ShadowStorage | Select-Object Volume, AllocatedSpace, UsedSpace, MaxSpace);',
  '  volumes = @(Get-CimInstance Win32_Volume -Filter "DriveType = 3" | Select-Object DriveLetter, DeviceID, Capacity, FreeSpace);',
  '  service = (Get-CimInstance Win32_Service -Filter "Name = \'VSS\' OR Name = \'swprv\'" | Select-Object Name, DisplayName, State, StartMode);',
  '  disabled = (Get-ItemProperty "HKLM:\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\SystemRestore" -Name DisableSR).DisableSR',
  '} | ConvertTo-Json -Depth 5 -Compress',
].join('\n');

const CREATE = [
  '$ErrorActionPreference = "Stop"',
  'try {',
  '  Checkpoint-Computer -Description "InfinitySniper HFX manual checkpoint" -RestorePointType "MODIFY_SETTINGS"',
  '  "OK"',
  '} catch {',
  '  "ERROR: " + $_.Exception.Message',
  '}',
].join('\n');

async function collect() {
  const result = await system.runPowerShellJson(QUERY, { timeoutMs: 90000 });
  if (!result.ok || !result.data) return null;
  return {
    points: system.asArray(result.data.points),
    shadow: system.asArray(result.data.shadow),
    volumes: system.asArray(result.data.volumes),
    services: system.asArray(result.data.service),
    disabled: result.data.disabled,
  };
}

/** Restore point timestamps use the DMTF format. */
function pointTime(point) {
  return system.formatWmiDate(point.CreationTime) || null;
}

module.exports = {
  name: 'System Restore Information',
  menuName: 'System Restore Information',
  description: 'System Protection state, reserved space and the available restore points.',
  version: '1.0.0',
  author: 'InfinitySniper HFX',
  category: 'Diagnostics',
  order: 70,
  requiredPermissions: 'normal',
  destructive: false,
  dependencies: [],
  minimumAppVersion: '1.0.0',
  permissions: ['system:read', 'wmi:query', 'system:restore-point(create, confirmed)'],
  tags: ['restore', 'system protection', 'checkpoint', 'backup', 'vss'],
  documentation:
    'Shows whether System Protection is turned on, how much shadow-copy space is reserved per ' +
    'volume, the state of the Volume Shadow Copy services and every restore point with its date, ' +
    'type and description. Creating a restore point is offered as a separate action that requires ' +
    'administrator rights and an explicit confirmation. Restore points are never deleted by this ' +
    'module, and it never starts a restore.',

  async selfTest(ctx) {
    if (!ctx.system.IS_WINDOWS) return { ok: false, message: 'Windows only' };
    const data = await collect();
    if (!data) return { ok: false, message: 'restore query failed' };
    return { ok: true, message: `${data.points.length} restore point(s)` };
  },

  async execute(ctx) {
    const { ui, prompt } = ctx;
    kit.header('System Restore Information', ['System Protection state and restore points.']);
    if (!kit.requireWindows('System restore information')) return { ok: false, reason: 'unsupported-platform' };

    const spin = ui.spinner('Reading System Restore configuration...');
    const data = await collect();
    spin.stop();
    if (!data) return kit.noData('System Restore information');

    const protectionOff = Number(data.disabled) === 1;
    const points = data.points.sort((a, b) => Number(b.SequenceNumber) - Number(a.SequenceNumber));

    ui.section('SYSTEM PROTECTION');
    ui.blank();
    kit.kv(
      'System Restore Status',
      protectionOff ? 'Disabled by policy' : points.length ? 'Enabled' : 'No restore point found',
      protectionOff ? 'brightRed' : points.length ? 'brightGreen' : 'brightYellow'
    );
    kit.kv('Restore Points', String(points.length));
    kit.kv('Newest Restore Point', points.length ? pointTime(points[0]) : null);
    for (const service of data.services) {
      kit.kv(
        `Service: ${system.clean(service.Name)}`,
        `${service.State} (${service.StartMode})`,
        String(service.State) === 'Running' ? 'brightGreen' : 'brightWhite'
      );
    }
    if (!ctx.isAdmin) {
      ui.println('  ' + ui.c.gray('Some values and creating a restore point require administrator rights.'));
    }

    if (data.shadow.length) {
      ui.blank();
      ui.section('RESERVED SPACE');
      ui.blank();
      kit.table(
        ['VOLUME', 'USED', 'ALLOCATED', 'MAXIMUM'],
        data.shadow.map((entry) => [
          ui.c.brightWhite(ui.truncate(String(entry.Volume && entry.Volume.DeviceID ? entry.Volume.DeviceID : entry.Volume), 20)),
          ui.c.brightCyan(system.formatBytes(entry.UsedSpace)),
          ui.c.gray(system.formatBytes(entry.AllocatedSpace)),
          ui.c.gray(system.formatBytes(entry.MaxSpace)),
        ]),
        { align: ['left', 'right', 'right', 'right'] }
      );
    }

    ui.blank();
    ui.section('RESTORE POINTS');
    ui.blank();
    if (!points.length) {
      ui.println('  ' + ui.c.gray('No restore point exists on this system.'));
      if (protectionOff) {
        ui.println('  ' + ui.c.gray('System Protection is disabled - Windows will not create any.'));
      }
    } else {
      kit.table(
        ['#', 'CREATED', 'TYPE', 'DESCRIPTION'],
        points.map((point) => [
          ui.c.gray(String(point.SequenceNumber)),
          ui.c.brightWhite(pointTime(point) || '-'),
          ui.c.gray(POINT_TYPES[Number(point.RestorePointType)] || String(point.RestorePointType)),
          ui.c.brightCyan(ui.truncate(system.clean(point.Description) || '-', 28)),
        ]),
        { align: ['right', 'left', 'left', 'left'], limit: 20 }
      );
    }

    // ---- optional action -------------------------------------------------
    ui.blank();
    ui.menu(
      [
        { key: '1', label: 'Export this information as a TXT report' },
        { key: '2', label: 'Create a restore point now (advanced)', color: 'brightYellow' },
        { separator: true },
        { key: '0', label: 'Back', color: 'gray' },
      ],
      { title: 'SYSTEM RESTORE' }
    );
    ui.blank();

    const answer = await prompt.select();
    if (answer === '1') {
      const report = kit.report('System Restore Report');
      const section = report.section('SYSTEM PROTECTION');
      section.add('System Restore Status', protectionOff ? 'Disabled' : 'Enabled');
      section.add('Restore Points', String(points.length));
      section.add('Newest Restore Point', points.length ? pointTime(points[0]) : null);
      const list = report.section('RESTORE POINTS');
      points.forEach((point) => {
        list.add(
          `#${point.SequenceNumber} - ${pointTime(point) || '?'}`,
          `${POINT_TYPES[Number(point.RestorePointType)] || point.RestorePointType} - ${system.clean(point.Description) || ''}`
        );
      });
      kit.saveReport(report, 'SystemRestore');
      await prompt.pause();
    } else if (answer === '2') {
      if (ctx.safeMode) {
        ui.blank();
        ui.warning('Safe Mode is enabled - creating a restore point is blocked.');
      } else if (ctx.dryRun) {
        ui.blank();
        ui.info('Dry Run: a restore point would be created. Nothing was changed.');
      } else if (!ctx.isAdmin) {
        ui.blank();
        ui.warning('Creating a restore point requires administrator rights.');
        ui.println('  ' + ui.c.gray('Restart the application as administrator and try again.'));
      } else {
        ui.blank();
        ui.println('  ' + ui.c.gray('A restore point lets Windows roll back system files and settings.'));
        const confirmed = await prompt.confirm('Create a restore point now?');
        if (confirmed === true) {
          const spin2 = ui.spinner('Asking Windows to create a restore point...');
          const outcome = await system.runPowerShell(CREATE, { timeoutMs: 180000 });
          spin2.stop();
          const text = outcome.stdout.trim();
          ui.blank();
          if (text.startsWith('OK')) {
            ui.completed('Restore point created.');
            ctx.logger.info('restore-info', 'Restore point created');
          } else {
            ui.error(`The restore point could not be created: ${text || outcome.stderr || 'unknown error'}`);
            ui.println('  ' + ui.c.gray('Windows limits how often restore points can be created automatically.'));
          }
        }
      }
      await prompt.pause();
    }

    return kit.done('System Restore information collected.');
  },
};
