/**
 * Function/Windows/services-viewer.js
 * ---------------------------------------------------------------------------
 * WINDOWS SERVICES VIEWER
 *
 * Lists services with state and startup type and can filter them. Starting or
 * stopping a service is an advanced action: administrator rights, an explicit
 * confirmation, blocked in Safe Mode, and never applied to a protected
 * Windows service.
 * ---------------------------------------------------------------------------
 */

'use strict';

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

/** Services that keep Windows usable - never offered for stopping. */
const PROTECTED = [
  'winlogon', 'csrss', 'services', 'lsass', 'smss', 'rpcss', 'dcomlaunch',
  'plugplay', 'power', 'profsvc', 'themes', 'audiosrv', 'eventlog', 'schedule',
  'samss', 'lanmanworkstation', 'netlogon', 'winmgmt', 'trustedinstaller',
  'wuauserv', 'mpssvc', 'windefend', 'securityhealthservice', 'bfe', 'dhcp', 'dnscache',
];

const QUERY = [
  '$ErrorActionPreference = "SilentlyContinue"',
  '@(Get-CimInstance Win32_Service | Select-Object Name, DisplayName, State, StartMode, StartName, PathName, Description, ProcessId, Status) | ConvertTo-Json -Depth 4 -Compress',
].join('\n');

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

const FILTERS = [
  { id: 'all', label: 'All services' },
  { id: 'running', label: 'Running services', test: (s) => String(s.State) === 'Running' },
  { id: 'stopped', label: 'Stopped services', test: (s) => String(s.State) === 'Stopped' },
  { id: 'auto', label: 'Automatic startup', test: (s) => String(s.StartMode) === 'Auto' },
  { id: 'manual', label: 'Manual startup', test: (s) => String(s.StartMode) === 'Manual' },
  { id: 'disabled', label: 'Disabled services', test: (s) => String(s.StartMode) === 'Disabled' },
  { id: 'problem', label: 'Automatic but not running', test: (s) => String(s.StartMode) === 'Auto' && String(s.State) !== 'Running' },
  { id: 'search', label: 'Search by name' },
];

function isProtected(service) {
  return PROTECTED.includes(String(service.Name || '').toLowerCase());
}

function stateCell(ui, service) {
  const state = String(service.State);
  if (state === 'Running') return ui.c.brightGreen(state);
  if (state === 'Stopped') return ui.c.gray(state);
  return ui.c.brightYellow(state);
}

function renderServices(ui, services, limit) {
  kit.table(
    ['SERVICE', 'DISPLAY NAME', 'STATE', 'STARTUP'],
    services.map((service) => [
      ui.c.brightWhite(ui.truncate(system.clean(service.Name) || '-', 22)),
      ui.c.gray(ui.truncate(system.clean(service.DisplayName) || '-', 28)),
      stateCell(ui, service),
      ui.c.gray(String(service.StartMode)),
    ]),
    { limit }
  );
}

/** Start or stop one service - always confirmed, never a protected one. */
async function changeService(ctx, service, action) {
  const { ui, prompt } = ctx;

  if (ctx.safeMode) {
    ui.blank();
    ui.warning('Safe Mode is enabled - services cannot be changed.');
    return false;
  }
  if (isProtected(service)) {
    ui.blank();
    ui.error(`"${service.Name}" is a protected Windows service and will not be touched.`);
    return false;
  }
  if (!ctx.isAdmin) {
    ui.blank();
    ui.warning('Starting or stopping a service requires administrator rights.');
    return false;
  }
  if (ctx.dryRun) {
    ui.blank();
    ui.info(`Dry Run: "${service.Name}" would be ${action === 'start' ? 'started' : 'stopped'}. Nothing was changed.`);
    return false;
  }

  ui.blank();
  ui.warning(`${action === 'start' ? 'Starting' : 'Stopping'} a service changes how Windows behaves right now.`);
  const confirmed = await prompt.confirm(
    `${action === 'start' ? 'Start' : 'Stop'} "${system.clean(service.DisplayName) || service.Name}"?`,
    { danger: action === 'stop' }
  );
  if (confirmed !== true) {
    ui.info('Nothing was changed.');
    return false;
  }

  const command =
    action === 'start'
      ? `Start-Service -Name "${service.Name}" -ErrorAction Stop; "OK"`
      : `Stop-Service -Name "${service.Name}" -Force:$false -ErrorAction Stop; "OK"`;

  const spin = ui.spinner(`${action === 'start' ? 'Starting' : 'Stopping'} ${service.Name}...`);
  const result = await system.runPowerShell(`$ErrorActionPreference = "Stop"\ntry { ${command} } catch { "ERROR: " + $_.Exception.Message }`, {
    timeoutMs: 60000,
  });
  spin.stop();

  const text = result.stdout.trim();
  ui.blank();
  if (text.startsWith('OK')) {
    ui.ok(`Service ${action === 'start' ? 'started' : 'stopped'}.`);
    ctx.logger.warn('services-viewer', `Service ${action}`, service.Name);
    return true;
  }
  ui.error(`The service could not be ${action === 'start' ? 'started' : 'stopped'}: ${text || result.stderr}`);
  return false;
}

module.exports = {
  name: 'Windows Services Viewer',
  menuName: 'Services Viewer',
  description: 'Lists Windows services with state and startup type, with filters and advanced control.',
  version: '1.0.0',
  author: 'InfinitySniper HFX',
  category: 'Windows',
  order: 20,
  requiredPermissions: 'normal',
  destructive: true,
  dependencies: [],
  minimumAppVersion: '1.0.0',
  permissions: ['system:read', 'wmi:query', 'service:control(confirmed, admin)'],
  tags: ['services', 'windows', 'startup', 'daemon'],
  documentation:
    'Lists every Windows service with its short name, display name, state and startup type, with ' +
    'filters for running, stopped, automatic, manual, disabled and "automatic but not running" - ' +
    'the filter that usually reveals a broken service. Starting or stopping a service is possible ' +
    'but is treated as an advanced action: it needs administrator rights and a confirmation, it is ' +
    'blocked in Safe Mode and in Dry Run, and a list of protected Windows services can never be ' +
    'stopped through this tool.',

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

  async execute(ctx) {
    const { ui, prompt } = ctx;
    kit.header('Services Viewer', ['Windows services with state and startup type.']);
    if (!kit.requireWindows('The services viewer')) return { ok: false, reason: 'unsupported-platform' };

    const spin = ui.spinner('Reading services...');
    let services = await collect();
    spin.stop();
    if (!services) return kit.noData('service information');

    let view = services.filter((s) => String(s.State) === 'Running');
    let title = 'RUNNING SERVICES';

    for (;;) {
      const running = services.filter((s) => String(s.State) === 'Running').length;
      const stopped = services.filter((s) => String(s.State) === 'Stopped').length;
      const broken = services.filter((s) => String(s.StartMode) === 'Auto' && String(s.State) !== 'Running').length;

      ui.blank();
      ui.section('SUMMARY');
      ui.blank();
      kit.kv('Total Services', system.formatNumber(services.length));
      kit.kv('Running', system.formatNumber(running), 'brightGreen');
      kit.kv('Stopped', system.formatNumber(stopped));
      kit.kv('Automatic But Not Running', system.formatNumber(broken), broken ? 'brightYellow' : 'brightGreen');

      ui.blank();
      ui.section(title);
      ui.blank();
      renderServices(ui, view, 22);

      ui.blank();
      ui.menu(
        [
          { key: '1', label: 'Change the filter' },
          { key: '2', label: 'Show service details' },
          { key: '3', label: 'Export the current view' },
          { key: '4', label: 'Start or stop a service (advanced)', color: 'brightYellow' },
          { key: '5', label: 'Refresh' },
          { separator: true },
          { key: '0', label: 'Back', color: 'gray' },
        ],
        { title: 'SERVICES' }
      );
      ui.blank();

      const answer = await prompt.select();
      if (!answer && prompt.isClosed()) break;
      if (answer === '0') break;

      switch (answer) {
        case '1': {
          const index = await prompt.choose('Which view?', FILTERS.map((f) => f.label));
          if (index === null) break;
          const filter = FILTERS[index];
          if (filter.id === 'search') {
            const term = (await prompt.text('Service name contains')).trim().toLowerCase();
            if (!term) break;
            view = services.filter(
              (service) =>
                String(service.Name || '').toLowerCase().includes(term) ||
                String(service.DisplayName || '').toLowerCase().includes(term)
            );
            title = `SEARCH: ${term.toUpperCase()} (${view.length})`;
          } else {
            view = filter.test ? services.filter(filter.test) : services;
            title = `${filter.label.toUpperCase()} (${view.length})`;
          }
          break;
        }

        case '2': {
          const index = await prompt.choose(
            'Which service?',
            view.slice(0, 30).map((service) => ({
              label: system.clean(service.DisplayName) || service.Name,
              hint: `${service.State} / ${service.StartMode}`,
            }))
          );
          if (index === null) break;
          const service = view[index];
          ui.blank();
          ui.section(String(system.clean(service.DisplayName) || service.Name).toUpperCase());
          ui.blank();
          kit.kv('Service Name', system.clean(service.Name));
          kit.kv('Display Name', system.clean(service.DisplayName));
          kit.kv('State', system.clean(service.State));
          kit.kv('Startup Type', system.clean(service.StartMode));
          kit.kv('Runs As', system.clean(service.StartName));
          kit.kv('Process ID', service.ProcessId ? String(service.ProcessId) : null);
          kit.kv('Status', system.clean(service.Status));
          kit.kv('Protected', isProtected(service) ? 'Yes - cannot be stopped here' : 'No');
          ui.blank();
          if (system.clean(service.PathName)) {
            ui.println('  ' + ui.c.gray('Executable:'));
            ui.println('  ' + ui.c.white(ui.truncate(system.clean(service.PathName), ui.getWidth())));
          }
          if (system.clean(service.Description)) {
            ui.blank();
            for (const line of ui.wrap(system.clean(service.Description), ui.getWidth() - 4)) {
              ui.println('  ' + ui.c.gray(line));
            }
          }
          await prompt.pause();
          break;
        }

        case '3': {
          const report = kit.report('Windows Services Report');
          const section = report.section('SUMMARY');
          section.add('Total Services', system.formatNumber(services.length));
          section.add('Running', system.formatNumber(running));
          section.add('Stopped', system.formatNumber(stopped));
          section.add('View', title);
          const list = report.section('SERVICES');
          view.forEach((service, index) => {
            list.add(
              `${index + 1}. ${system.clean(service.Name)}`,
              `${system.clean(service.DisplayName) || ''} | ${service.State} | ${service.StartMode}`
            );
          });
          kit.saveReport(report, 'Services');
          await prompt.pause();
          break;
        }

        case '4': {
          const index = await prompt.choose(
            'Which service?',
            view.slice(0, 30).map((service) => ({
              label: system.clean(service.DisplayName) || service.Name,
              hint: `${service.State}${isProtected(service) ? ' - protected' : ''}`,
            }))
          );
          if (index === null) break;
          const service = view[index];
          const action = String(service.State) === 'Running' ? 'stop' : 'start';
          const changed = await changeService(ctx, service, action);
          if (changed) {
            const refresh = ui.spinner('Refreshing services...');
            services = (await collect()) || services;
            refresh.stop();
            view = services.filter((s) => String(s.State) === 'Running');
            title = 'RUNNING SERVICES';
          }
          await prompt.pause();
          break;
        }

        case '5': {
          const refresh = ui.spinner('Refreshing services...');
          services = (await collect()) || services;
          refresh.stop();
          view = services.filter((s) => String(s.State) === 'Running');
          title = 'RUNNING SERVICES';
          break;
        }

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

    return kit.done('Services viewer closed.');
  },
};
