/**
 * Function/Diagnostics/firewall-status.js
 * ---------------------------------------------------------------------------
 * FIREWALL STATUS
 *
 * State of the Domain, Private and Public firewall profiles, the default
 * actions, logging settings and a summary of the active rules.
 * Read-only - no rule is added, changed or removed.
 * ---------------------------------------------------------------------------
 */

'use strict';

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

const QUERY = [
  '$ErrorActionPreference = "SilentlyContinue"',
  '[ordered]@{',
  '  profiles = @(Get-NetFirewallProfile | Select-Object Name, Enabled, DefaultInboundAction, DefaultOutboundAction, AllowInboundRules, NotifyOnListen, LogAllowed, LogBlocked, LogFileName, LogMaxSizeKilobytes);',
  '  service = (Get-CimInstance Win32_Service -Filter "Name = \'MpsSvc\'" | Select-Object -First 1 Name, DisplayName, State, StartMode);',
  '  ruleCounts = @(Get-NetFirewallRule | Group-Object -Property Direction, Enabled | Select-Object Name, Count);',
  '  blockedInbound = @(Get-NetFirewallRule -Enabled True -Direction Inbound -Action Block | Select-Object -First 15 DisplayName, Profile);',
  '  recentAllow = @(Get-NetFirewallRule -Enabled True -Direction Inbound -Action Allow | Select-Object -First 15 DisplayName, Profile, Group)',
  '} | ConvertTo-Json -Depth 5 -Compress',
].join('\n');

async function collect() {
  const result = await system.runPowerShellJson(QUERY, { timeoutMs: 90000 });
  if (!result.ok || !result.data) return null;
  return {
    profiles: system.asArray(result.data.profiles),
    service: result.data.service || {},
    ruleCounts: system.asArray(result.data.ruleCounts),
    blockedInbound: system.asArray(result.data.blockedInbound),
    recentAllow: system.asArray(result.data.recentAllow),
  };
}

function enabledOf(profile) {
  return profile.Enabled === true || Number(profile.Enabled) === 1;
}

function actionText(value) {
  const text = String(value);
  if (text === '2' || text.toLowerCase() === 'block') return 'Block';
  if (text === '1' || text.toLowerCase() === 'allow') return 'Allow';
  return text === 'undefined' ? null : text;
}

module.exports = {
  name: 'Firewall Status',
  menuName: 'Firewall Status',
  description: 'Domain, Private and Public firewall profiles with default actions and rule counts.',
  version: '1.0.0',
  author: 'InfinitySniper HFX',
  category: 'Diagnostics',
  order: 50,
  requiredPermissions: 'normal',
  destructive: false,
  dependencies: [],
  minimumAppVersion: '1.0.0',
  permissions: ['system:read', 'firewall:read', 'filesystem:write(reports)'],
  tags: ['firewall', 'security', 'network', 'profiles', 'rules'],
  documentation:
    'Shows whether the Windows Defender Firewall is active for each of the three network profiles, ' +
    'what the default inbound and outbound actions are, whether blocked and allowed connections are ' +
    'logged, and how many rules exist. A few inbound block and allow rules are listed as examples. ' +
    'This module only reads the configuration; it never adds, changes or deletes a rule.',

  async selfTest(ctx) {
    if (!ctx.system.IS_WINDOWS) return { ok: false, message: 'Windows only' };
    const data = await collect();
    return data && data.profiles.length
      ? { ok: true, message: `${data.profiles.length} firewall profile(s)` }
      : { ok: false, message: 'firewall status unavailable' };
  },

  async execute(ctx) {
    const { ui } = ctx;
    kit.header('Firewall Status', ['Windows Defender Firewall profiles and rules.', 'Read-only.']);
    if (!kit.requireWindows('The firewall status')) return { ok: false, reason: 'unsupported-platform' };

    const spin = ui.spinner('Reading firewall configuration...');
    const data = await collect();
    spin.stop();
    if (!data || !data.profiles.length) return kit.noData('firewall information');

    const active = data.profiles.filter(enabledOf);

    ui.section('SUMMARY');
    ui.blank();
    kit.kv('Firewall Service', system.clean(data.service.State), String(data.service.State) === 'Running' ? 'brightGreen' : 'brightRed');
    kit.kv('Service Startup', system.clean(data.service.StartMode));
    kit.kv('Profiles Enabled', `${active.length} of ${data.profiles.length}`, active.length === data.profiles.length ? 'brightGreen' : 'brightYellow');

    for (const profile of data.profiles) {
      const enabled = enabledOf(profile);
      ui.blank();
      ui.section(`${String(profile.Name).toUpperCase()} PROFILE`);
      ui.blank();
      kit.kv('Status', enabled ? 'Enabled' : 'Disabled', enabled ? 'brightGreen' : 'brightRed');
      kit.kv('Default Inbound Action', actionText(profile.DefaultInboundAction));
      kit.kv('Default Outbound Action', actionText(profile.DefaultOutboundAction));
      kit.kv('Inbound Rules Allowed', profile.AllowInboundRules === undefined ? null : String(profile.AllowInboundRules));
      kit.kv('Notify On Listen', profile.NotifyOnListen === undefined ? null : String(profile.NotifyOnListen));
      kit.kv('Log Blocked Connections', profile.LogBlocked === undefined ? null : String(profile.LogBlocked));
      kit.kv('Log Allowed Connections', profile.LogAllowed === undefined ? null : String(profile.LogAllowed));
      kit.kv('Log File', system.clean(profile.LogFileName));
    }

    if (data.ruleCounts.length) {
      ui.blank();
      ui.section('RULES');
      ui.blank();
      kit.table(
        ['DIRECTION / ENABLED', 'RULES'],
        data.ruleCounts.map((group) => [
          ui.c.brightWhite(String(group.Name)),
          ui.c.brightCyan(system.formatNumber(group.Count)),
        ]),
        { align: ['left', 'right'] }
      );
    }

    if (data.recentAllow.length) {
      ui.blank();
      ui.section('EXAMPLE INBOUND ALLOW RULES');
      ui.blank();
      for (const rule of data.recentAllow.slice(0, 8)) {
        ui.println(
          '  ' + ui.c.gray(ui.glyphs().bullet + ' ') +
            ui.c.brightWhite(ui.truncate(system.clean(rule.DisplayName) || 'Unnamed rule', 40)) +
            ui.c.gray(`  [${system.clean(rule.Profile) || 'Any'}]`)
        );
      }
    }

    ui.blank();
    const disabled = data.profiles.filter((profile) => !enabledOf(profile));
    if (disabled.length) {
      ui.warning(`${disabled.length} firewall profile(s) are disabled: ${disabled.map((p) => p.Name).join(', ')}`);
      ui.println('  ' + ui.c.gray('Enable them in Windows Security - this tool does not change firewall settings.'));
    } else {
      ui.completed('The firewall is active on every profile.');
    }

    await kit.offerExport('Firewall Status Report', 'FirewallStatus', (report) => {
      const section = report.section('FIREWALL');
      section.add('Firewall Service', system.clean(data.service.State));
      section.add('Profiles Enabled', `${active.length} of ${data.profiles.length}`);
      for (const profile of data.profiles) {
        const group = section.group(`${profile.Name} Profile`);
        group.add('Status', enabledOf(profile) ? 'Enabled' : 'Disabled');
        group.add('Default Inbound Action', actionText(profile.DefaultInboundAction));
        group.add('Default Outbound Action', actionText(profile.DefaultOutboundAction));
        group.add('Log Blocked Connections', String(profile.LogBlocked));
        group.add('Log File', system.clean(profile.LogFileName));
      }
      const rules = report.section('RULE COUNTS');
      for (const group of data.ruleCounts) rules.add(String(group.Name), system.formatNumber(group.Count));
    });

    return kit.done('Firewall status collected.');
  },
};
