/**
 * Function/Network/hosts-viewer.js
 * ---------------------------------------------------------------------------
 * HOSTS FILE VIEWER
 *
 * View, search and back up the Windows hosts file. Editing is an advanced
 * action: it needs administrator rights, an explicit confirmation, and it
 * always writes a backup first.
 * ---------------------------------------------------------------------------
 */

'use strict';

const fs = require('fs');
const path = require('path');
const { execFile } = require('child_process');
const kit = require('../../core/kit');
const system = require('../../core/system');

const HOSTS_FILE = path.join(process.env.SystemRoot || 'C:\\Windows', 'System32', 'drivers', 'etc', 'hosts');

function readHosts() {
  try {
    const text = fs.readFileSync(HOSTS_FILE, 'utf8');
    const lines = text.split(/\r?\n/);
    const entries = [];

    lines.forEach((line, index) => {
      const trimmed = line.trim();
      if (!trimmed || trimmed.startsWith('#')) return;
      const match = trimmed.match(/^(\S+)\s+(.+?)(?:\s+#.*)?$/);
      if (!match) return;
      const hosts = match[2].split(/\s+/).filter(Boolean);
      entries.push({ line: index + 1, address: match[1], hosts });
    });

    return { ok: true, text, lines, entries };
  } catch (err) {
    return { ok: false, error: err.message };
  }
}

/** Copy the hosts file into the backups folder. */
function backupHosts(ctx) {
  try {
    const target = path.join(ctx.paths.backups, `hosts_${ctx.logger.fileStamp()}.txt`);
    fs.copyFileSync(HOSTS_FILE, target);
    return { ok: true, file: target };
  } catch (err) {
    return { ok: false, error: err.message };
  }
}

module.exports = {
  name: 'Hosts File Viewer',
  menuName: 'Hosts File Viewer',
  description: 'View, search and back up the Windows hosts file. Editing needs administrator rights.',
  version: '1.0.0',
  author: 'InfinitySniper HFX',
  category: 'Network',
  order: 80,
  requiredPermissions: 'normal',
  destructive: false,
  dependencies: [],
  minimumAppVersion: '1.0.0',
  permissions: ['filesystem:read(hosts)', 'filesystem:write(backups)'],
  tags: ['hosts', 'dns', 'network', 'file'],
  documentation:
    'Shows the active entries of %SystemRoot%\\System32\\drivers\\etc\\hosts, lets you search them and ' +
    'writes a timestamped backup into the backups folder. Editing opens the file in Notepad and ' +
    'requires administrator rights - Windows refuses to save it otherwise. A backup is always ' +
    'created before the editor opens. This module never rewrites the file by itself.',

  async selfTest() {
    const result = readHosts();
    return result.ok
      ? { ok: true, message: `${result.entries.length} active entry/entries` }
      : { ok: false, message: `hosts file unreadable: ${result.error}` };
  },

  async execute(ctx) {
    const { ui, prompt } = ctx;
    kit.header('Hosts File Viewer', [ui.truncate(HOSTS_FILE, 58), 'Editing requires administrator rights.']);
    if (!kit.requireWindows('The hosts file viewer')) return { ok: false, reason: 'unsupported-platform' };

    for (;;) {
      const data = readHosts();
      if (!data.ok) {
        ui.blank();
        ui.error(`The hosts file could not be read: ${data.error}`);
        return { ok: false, reason: 'unreadable' };
      }

      ui.blank();
      ui.section('SUMMARY');
      ui.blank();
      kit.kv('File', HOSTS_FILE);
      kit.kv('Total Lines', system.formatNumber(data.lines.length));
      kit.kv('Active Entries', system.formatNumber(data.entries.length));
      kit.kv('Size', system.formatBytes(Buffer.byteLength(data.text, 'utf8')));
      kit.kv('Administrator Mode', ctx.isAdmin ? 'YES (editing possible)' : 'NO (read-only)');

      ui.blank();
      ui.menu(
        [
          { key: '1', label: 'View active entries' },
          { key: '2', label: 'View the complete file' },
          { key: '3', label: 'Search the file' },
          { key: '4', label: 'Create a backup' },
          { key: '5', label: 'Export as a TXT report' },
          { key: '6', label: 'Edit in Notepad (advanced)', color: 'brightYellow' },
          { separator: true },
          { key: '0', label: 'Back', color: 'gray' },
        ],
        { title: 'HOSTS FILE' }
      );
      ui.blank();

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

      switch (answer) {
        case '1': {
          ui.blank();
          ui.section('ACTIVE ENTRIES');
          ui.blank();
          if (!data.entries.length) {
            ui.println('  ' + ui.c.gray('The hosts file contains no active entry (only comments).'));
          } else {
            kit.table(
              ['LINE', 'ADDRESS', 'HOST NAME(S)'],
              data.entries.map((entry) => [
                ui.c.gray(String(entry.line)),
                ui.c.brightWhite(entry.address),
                ui.c.brightCyan(ui.truncate(entry.hosts.join(', '), 36)),
              ]),
              { align: ['right', 'left', 'left'], limit: 30 }
            );
          }
          await prompt.pause();
          break;
        }

        case '2': {
          ui.blank();
          ui.section('HOSTS FILE');
          ui.blank();
          const shown = data.lines.slice(0, 60);
          for (const line of shown) {
            const trimmed = line.trim();
            const color = !trimmed ? 'gray' : trimmed.startsWith('#') ? 'gray' : 'brightWhite';
            ui.println('  ' + ui.c[color](ui.truncate(line, ui.getWidth())));
          }
          if (data.lines.length > shown.length) {
            ui.blank();
            ui.println('  ' + ui.c.gray(`... and ${data.lines.length - shown.length} more line(s)`));
          }
          await prompt.pause();
          break;
        }

        case '3': {
          const term = (await prompt.text('Search for')).trim().toLowerCase();
          if (!term) break;
          const matches = data.lines
            .map((line, index) => ({ line, number: index + 1 }))
            .filter((entry) => entry.line.toLowerCase().includes(term));

          ui.blank();
          ui.section(`SEARCH: ${term.toUpperCase()}`);
          ui.blank();
          if (!matches.length) {
            ui.println('  ' + ui.c.gray('No line matches.'));
          } else {
            for (const match of matches.slice(0, 30)) {
              ui.println('  ' + ui.c.gray(ui.padStart(String(match.number), 5) + '  ') + ui.c.brightWhite(ui.truncate(match.line, ui.getWidth() - 8)));
            }
            if (matches.length > 30) ui.println('  ' + ui.c.gray(`... and ${matches.length - 30} more`));
          }
          await prompt.pause();
          break;
        }

        case '4': {
          const backup = backupHosts(ctx);
          ui.blank();
          if (backup.ok) {
            ui.ok('Backup created.');
            ui.println('  ' + ui.c.gray('Location: ') + ui.c.brightCyan(backup.file));
            ctx.logger.info('hosts-viewer', 'Hosts file backed up', backup.file);
          } else {
            ui.error(`The backup failed: ${backup.error}`);
          }
          await prompt.pause();
          break;
        }

        case '5': {
          const report = kit.report('Hosts File Report');
          const section = report.section('SUMMARY');
          section.add('File', HOSTS_FILE);
          section.add('Total Lines', system.formatNumber(data.lines.length));
          section.add('Active Entries', system.formatNumber(data.entries.length));
          const entries = report.section('ACTIVE ENTRIES');
          data.entries.forEach((entry, index) => {
            entries.add(`${index + 1}. ${entry.address}`, entry.hosts.join(', '));
          });
          const raw = report.section('FILE CONTENT');
          data.lines.forEach((line) => raw.note(line));
          kit.saveReport(report, 'HostsFile');
          await prompt.pause();
          break;
        }

        case '6': {
          if (ctx.safeMode) {
            ui.blank();
            ui.warning('Safe Mode is enabled - editing the hosts file is blocked.');
            await prompt.pause();
            break;
          }
          ui.blank();
          if (!ctx.isAdmin) {
            ui.warning('Editing the hosts file requires administrator rights.');
            ui.println('  ' + ui.c.gray('Restart the application as administrator, then try again.'));
            ui.println('  ' + ui.c.gray('Notepad can still open the file, but Windows will refuse to save it.'));
          }
          ui.println('  ' + ui.c.gray('A backup is created before the editor opens.'));
          const confirmed = await prompt.confirm('Open the hosts file in Notepad?', { danger: true });
          if (confirmed !== true) break;

          const backup = backupHosts(ctx);
          if (backup.ok) {
            ui.ok(`Backup written to ${backup.file}`);
          } else {
            ui.warning(`No backup could be written: ${backup.error}`);
          }

          try {
            execFile('notepad.exe', [HOSTS_FILE], { windowsHide: false }, () => {});
            ui.ok('Notepad was opened with the hosts file.');
            ctx.logger.warn('hosts-viewer', 'Hosts file opened for editing', { admin: ctx.isAdmin });
          } catch (err) {
            ui.error(`Notepad could not be started: ${err.message}`);
          }
          await prompt.pause();
          break;
        }

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

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