'use strict';

// Desinstala servicios Windows de ARKHON.
// Ejecutar como Administrador: node scripts/uninstall-service.js [--json]

const fs = require('fs');
const path = require('path');
const { execFileSync } = require('child_process');

const args = new Set(process.argv.slice(2));
const jsonMode = args.has('--json');

const ROOT = path.resolve(__dirname, '..');
const PROGRAMDATA = process.env.ProgramData || 'C:\\ProgramData';
const DIAGNOSTIC_PATH = path.join(PROGRAMDATA, 'ARKHON', 'service-uninstall-diagnostics.json');

const SERVICE_NAMES = [
  'ARKHON Updater',
  'ARKHON Agent',
  'ARKHON Monitor',
  'ArkhonMonitorConnector',
  'arkhonagent',
  'arkhonagent.exe',
  'arkhonupdater',
  'arkhonupdater.exe',
];

const result = {
  ok: false,
  action: 'uninstall',
  services: [],
  errors: [],
  warnings: [],
  diagnosticPath: DIAGNOSTIC_PATH,
};

function print(message) {
  if (!jsonMode) console.log(message);
}

function addWarning(message) {
  result.warnings.push(message);
  print(`[WARN] ${message}`);
}

function addError(message) {
  result.errors.push(message);
  print(`[ERROR] ${message}`);
}

function finish(code) {
  result.ok = result.errors.length === 0;
  try {
    fs.mkdirSync(path.dirname(DIAGNOSTIC_PATH), { recursive: true });
    fs.writeFileSync(DIAGNOSTIC_PATH, JSON.stringify(result, null, 2), 'utf8');
  } catch (error) {
    result.warnings.push(`No se pudo escribir diagnostico: ${error.message}`);
  }

  if (jsonMode) process.stdout.write(`${JSON.stringify(result)}\n`);
  process.exit(code);
}

function requireAdmin() {
  try {
    execFileSync('net.exe', ['session'], { stdio: 'pipe', timeout: 8000 });
  } catch (_) {
    throw new Error('Debes ejecutar este script como Administrador.');
  }
}

function run(command, argsList, options = {}) {
  return execFileSync(command, argsList, {
    cwd: options.cwd || ROOT,
    stdio: 'pipe',
    timeout: options.timeout || 20000,
    windowsHide: true,
  }).toString();
}

function tryRun(command, argsList, options = {}) {
  try {
    return { ok: true, stdout: run(command, argsList, options) };
  } catch (error) {
    return { ok: false, error, stdout: error.stdout ? error.stdout.toString() : '', stderr: error.stderr ? error.stderr.toString() : '' };
  }
}

function serviceExists(name) {
  return tryRun('sc.exe', ['query', name], { timeout: 8000 }).ok;
}

function getServiceCim(name) {
  const ps = [
    '$ErrorActionPreference = "Stop"',
    `$svc = Get-CimInstance Win32_Service -Filter "Name='${name.replace(/'/g, "''")}'"`,
    'if ($null -eq $svc) { exit 3 }',
    '$svc | Select-Object Name,DisplayName,State,StartMode,StartName,PathName | ConvertTo-Json -Compress',
  ].join('; ');
  const probe = tryRun('powershell.exe', ['-NoProfile', '-ExecutionPolicy', 'Bypass', '-Command', ps], { timeout: 10000 });
  if (!probe.ok || !probe.stdout.trim()) return null;
  return JSON.parse(probe.stdout);
}

function waitForDeletion(name) {
  const started = Date.now();
  while (Date.now() - started < 30000) {
    if (!serviceExists(name)) return true;
    Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 500);
  }
  return !serviceExists(name);
}

function stopAndDeleteWithSc(name) {
  if (!serviceExists(name)) return false;
  tryRun('sc.exe', ['stop', name], { timeout: 15000 });
  const deleted = tryRun('sc.exe', ['delete', name], { timeout: 15000 });
  if (!deleted.ok) throw new Error(`No se pudo eliminar ${name}: ${deleted.stderr || deleted.stdout || deleted.error.message}`);
  return true;
}

function removeService(name) {
  const before = getServiceCim(name);
  if (!before && !serviceExists(name)) {
    result.services.push({ name, existed: false, removed: true, stateBefore: null, valid: true });
    return;
  }

  stopAndDeleteWithSc(name);
  const removed = waitForDeletion(name);
  const after = getServiceCim(name);
  const valid = removed && !after;

  if (!valid) addError(`${name}: Get-CimInstance/sc.exe aun detectan el servicio despues de desinstalar.`);

  result.services.push({
    name,
    existed: true,
    removed: valid,
    stateBefore: before ? before.State : null,
    startModeBefore: before ? before.StartMode : null,
    startNameBefore: before ? before.StartName : null,
    pathNameBefore: before ? before.PathName : null,
    valid,
  });
}

function main() {
  print('ARKHON - desinstalar servicios Windows');
  requireAdmin();
  for (const name of SERVICE_NAMES) {
    removeService(name);
  }
  addWarning('Se preservan C:\\ProgramData\\ARKHON\\Agent y C:\\ProgramData\\ARKHON\\Updater.');
}

try {
  main();
  finish(result.errors.length === 0 ? 0 : 1);
} catch (error) {
  addError(error.message || String(error));
  finish(1);
}
