/**
 * Function/Diagnostics/event-log-summary.js
 * ---------------------------------------------------------------------------
 * EVENT VIEWER SUMMARY
 *
 * A readable digest of the Windows event logs: system errors, application
 * errors, critical events and unexpected shutdowns - grouped by source instead
 * of dumping thousands of raw records. Read-only.
 * ---------------------------------------------------------------------------
 */

'use strict';

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

/** Event ids that mean "the machine went down badly". */
const SHUTDOWN_IDS = [41, 6008, 1001];

function buildQuery(days, maxEvents) {
  return [
    '$ErrorActionPreference = "SilentlyContinue"',
    `$start = (Get-Date).AddDays(-${days})`,
    `$max = ${maxEvents}`,
    'function Grab($log, $levels) {',
    '  @(Get-WinEvent -FilterHashtable @{ LogName = $log; Level = $levels; StartTime = $start } -MaxEvents $max |',
    '    Select-Object TimeCreated, Id, ProviderName, LevelDisplayName, @{n="Message";e={ if ($_.Message) { $_.Message.Split("`n")[0].Trim() } else { $null } }})',
    '}',
    '[ordered]@{',
    '  system = (Grab "System" @(1,2));',
    '  application = (Grab "Application" @(1,2));',
    `  shutdowns = @(Get-WinEvent -FilterHashtable @{ LogName = "System"; Id = ${SHUTDOWN_IDS.join(',')}; StartTime = $start } -MaxEvents 40 | Select-Object TimeCreated, Id, ProviderName, @{n="Message";e={ if ($_.Message) { $_.Message.Split("\`n")[0].Trim() } else { $null } }})`,
    '} | ConvertTo-Json -Depth 5 -Compress',
  ].join('\n');
}

async function collect(days, maxEvents) {
  const result = await system.runPowerShellJson(buildQuery(days, maxEvents), { timeoutMs: 120000 });
  if (!result.ok || !result.data) return null;
  return {
    system: system.asArray(result.data.system),
    application: system.asArray(result.data.application),
    shutdowns: system.asArray(result.data.shutdowns),
  };
}

/** Group events by provider so the user sees the source, not 500 lines. */
function groupBySource(events) {
  const map = new Map();
  for (const event of events) {
    const key = system.clean(event.ProviderName) || 'Unknown';
    const entry = map.get(key) || { source: key, count: 0, critical: 0, latest: null, sample: null, ids: new Set() };
    entry.count += 1;
    if (String(event.LevelDisplayName).toLowerCase() === 'critical') entry.critical += 1;
    entry.ids.add(event.Id);
    const time = system.formatWmiDate(event.TimeCreated);
    if (!entry.latest || String(time) > String(entry.latest)) {
      entry.latest = time;
      entry.sample = system.clean(event.Message);
    }
    map.set(key, entry);
  }
  return [...map.values()].sort((a, b) => b.count - a.count);
}

function renderGroups(ui, groups, limit) {
  if (!groups.length) {
    ui.println('  ' + ui.c.brightGreen('None in this period.'));
    return;
  }
  kit.table(
    ['SOURCE', 'EVENTS', 'CRITICAL', 'LAST OCCURRENCE'],
    groups.map((group) => [
      ui.c.brightWhite(ui.truncate(group.source, 30)),
      ui.c.brightYellow(String(group.count)),
      group.critical ? ui.c.brightRed(String(group.critical)) : ui.c.gray('0'),
      ui.c.gray(group.latest || '-'),
    ]),
    { align: ['left', 'right', 'right', 'left'], limit }
  );
}

module.exports = {
  name: 'Event Log Summary',
  menuName: 'Event Log Summary',
  description: 'Digest of system and application errors, critical events and unexpected shutdowns.',
  version: '1.0.0',
  author: 'InfinitySniper HFX',
  category: 'Diagnostics',
  order: 20,
  requiredPermissions: 'normal',
  destructive: false,
  dependencies: [],
  minimumAppVersion: '1.0.0',
  permissions: ['eventlog:read', 'filesystem:write(reports)'],
  tags: ['events', 'errors', 'log', 'eventvwr', 'diagnostics'],
  config: { days: 7, maxEvents: 400 },
  documentation:
    'Reads the System and Application event logs for errors and critical events in a chosen period ' +
    'and groups them by source, showing how often each source failed and when it last happened, ' +
    'instead of printing thousands of raw records. Unexpected shutdowns (event 41, 6008 and 1001) ' +
    'are listed separately because they usually point at power loss or a bug check. ' +
    'Some logs require administrator rights to read completely.',

  async selfTest(ctx) {
    if (!ctx.system.IS_WINDOWS) return { ok: false, message: 'Windows only' };
    const probe = await system.runPowerShellJson(
      '@(Get-WinEvent -LogName System -MaxEvents 1 | Select-Object Id) | ConvertTo-Json -Compress',
      { timeoutMs: 30000 }
    );
    return probe.ok ? { ok: true, message: 'event log readable' } : { ok: false, message: 'event log not readable' };
  },

  async execute(ctx) {
    const { ui, prompt, config } = ctx;
    kit.header('Event Log Summary', ['Errors and critical events, grouped by source.']);
    if (!kit.requireWindows('The event log summary')) return { ok: false, reason: 'unsupported-platform' };

    const periods = [
      { label: 'Last 24 hours', days: 1 },
      { label: 'Last 7 days', days: 7 },
      { label: 'Last 30 days', days: 30 },
    ];
    const choice = await prompt.choose('Which period?', periods.map((p) => p.label));
    if (choice === null) return kit.done('Cancelled.');
    const days = periods[choice].days;

    const spin = ui.spinner(`Reading the event logs (${days} day period)...`);
    const data = await collect(days, Number(config.maxEvents) || 400);
    spin.stop();

    if (!data) {
      ui.blank();
      ui.warning('The event logs could not be read.');
      ui.println('  ' + ui.c.gray('Reading the Security and some System entries requires administrator rights.'));
      return { ok: false, reason: 'no-access' };
    }

    const systemGroups = groupBySource(data.system);
    const appGroups = groupBySource(data.application);
    const criticalCount =
      data.system.filter((e) => String(e.LevelDisplayName).toLowerCase() === 'critical').length +
      data.application.filter((e) => String(e.LevelDisplayName).toLowerCase() === 'critical').length;

    ui.blank();
    ui.section('SUMMARY');
    ui.blank();
    kit.kv('Period', `Last ${days} day(s)`);
    kit.kv('System Errors', system.formatNumber(data.system.length), data.system.length ? 'brightYellow' : 'brightGreen');
    kit.kv('Application Errors', system.formatNumber(data.application.length), data.application.length ? 'brightYellow' : 'brightGreen');
    kit.kv('Critical Events', system.formatNumber(criticalCount), criticalCount ? 'brightRed' : 'brightGreen');
    kit.kv('Unexpected Shutdowns', system.formatNumber(data.shutdowns.length), data.shutdowns.length ? 'brightRed' : 'brightGreen');
    if (!ctx.isAdmin) ui.println('  ' + ui.c.gray('Running as administrator gives a more complete picture.'));

    ui.blank();
    ui.section('SYSTEM ERRORS BY SOURCE');
    ui.blank();
    renderGroups(ui, systemGroups, 12);

    ui.blank();
    ui.section('APPLICATION ERRORS BY SOURCE');
    ui.blank();
    renderGroups(ui, appGroups, 12);

    ui.blank();
    ui.section('UNEXPECTED SHUTDOWNS');
    ui.blank();
    if (!data.shutdowns.length) {
      ui.println('  ' + ui.c.brightGreen('None - Windows shut down cleanly in this period.'));
    } else {
      for (const event of data.shutdowns.slice(0, 10)) {
        ui.println(
          '  ' + ui.c.brightRed(ui.glyphs().bullet + ' ') +
            ui.c.brightWhite(ui.padEnd(system.formatWmiDate(event.TimeCreated) || '?', 20)) +
            ui.c.gray(`Event ${event.Id} - ${ui.truncate(system.clean(event.Message) || system.clean(event.ProviderName) || '', 30)}`)
        );
      }
    }

    // A short "what does this mean" hint keeps the screen useful for non-experts.
    ui.blank();
    if (data.shutdowns.length) {
      ui.warning('Unexpected shutdowns usually mean power loss, overheating or a blue screen.');
      ui.println('  ' + ui.c.gray('The Crash Summary function has the bug check details.'));
    }

    await kit.offerExport('Event Log Summary', 'EventLogs', (report) => {
      const section = report.section('SUMMARY');
      section.add('Period', `Last ${days} day(s)`);
      section.add('System Errors', system.formatNumber(data.system.length));
      section.add('Application Errors', system.formatNumber(data.application.length));
      section.add('Critical Events', system.formatNumber(criticalCount));
      section.add('Unexpected Shutdowns', system.formatNumber(data.shutdowns.length));

      const systemSection = report.section('SYSTEM ERRORS BY SOURCE');
      systemGroups.forEach((group, index) => {
        const entry = systemSection.group(`${index + 1}. ${group.source}`);
        entry.add('Events', String(group.count));
        entry.add('Critical', String(group.critical));
        entry.add('Event IDs', [...group.ids].slice(0, 10).join(', '));
        entry.add('Last Occurrence', group.latest);
        entry.add('Example', group.sample);
      });

      const appSection = report.section('APPLICATION ERRORS BY SOURCE');
      appGroups.forEach((group, index) => {
        const entry = appSection.group(`${index + 1}. ${group.source}`);
        entry.add('Events', String(group.count));
        entry.add('Last Occurrence', group.latest);
        entry.add('Example', group.sample);
      });

      const shutdowns = report.section('UNEXPECTED SHUTDOWNS');
      data.shutdowns.forEach((event, index) => {
        shutdowns.add(
          `${index + 1}. ${system.formatWmiDate(event.TimeCreated) || '?'}`,
          `Event ${event.Id} - ${system.clean(event.Message) || system.clean(event.ProviderName) || ''}`
        );
      });
    });

    return kit.done('Event log summary finished.');
  },
};
