#!/usr/bin/env node
// TagAlly Engine — Startvorlauf.
//
//   node start.js
//
// Warum es das gibt: Der Port 8474 ist fest vergeben. Läuft nach einem Update
// noch die alte Engine, dann belegt sie den Port, ein zweiter Start scheitert
// mit EADDRINUSE, und wer die frühere Fassung der Startskripte benutzte, bekam
// sogar die beruhigende Auskunft „läuft bereits". Ergebnis: Man arbeitet
// unbemerkt mit der Vorgängerversion weiter.
//
// Dieser Vorlauf vergleicht deshalb die laufende Version mit der auf der
// Platte und löst eine veraltete Engine ab, bevor er die neue startet.

const { VERSION } = require("./validate.js");
const { translator, detect } = require("./i18n.js");

const t = translator(detect());

const PORT = 8474;
const BASIS = `http://127.0.0.1:${PORT}`;

function warte(ms) {
  return new Promise((r) => setTimeout(r, ms));
}

async function laufende() {
  try {
    const res = await fetch(BASIS + "/health", { signal: AbortSignal.timeout(1500) });
    if (!res.ok) return null;
    return await res.json();
  } catch (e) {
    return null; // niemand da, oder es antwortet jedenfalls nicht wie wir
  }
}

async function beenden() {
  try {
    await fetch(BASIS + "/shutdown", { method: "POST", signal: AbortSignal.timeout(2000) });
  } catch (e) {
    // Eine Engine, die beim Beenden die Verbindung abreißen lässt, ist genau
    // das erwartete Verhalten — kein Grund zur Sorge.
  }
  // Warten, bis der Port wirklich frei ist.
  for (let i = 0; i < 40; i++) {
    if (!(await laufende())) return true;
    await warte(250);
  }
  return false;
}

async function main() {
  const alt = await laufende();

  if (alt && alt.version === VERSION) {
    console.log(t("console.alreadyRunning", { version: VERSION, url: BASIS }));
    console.log(t("console.closeWindow"));
    return;
  }

  if (alt) {
    console.log(t("console.olderRunning", { running: alt.version, local: VERSION }));
    console.log(t("console.replacing"));
    if (!(await beenden())) {
      // Kommt vor allem bei Engines vor, die älter sind als /shutdown selbst.
      const win = process.platform === "win32";
      console.error("");
      console.error(t("console.stopFailed"));
      console.error(t("console.stopFailedHint"));
      console.error("");
      console.error(win
        ? `  for /f "tokens=5" %a in ('netstat -ano ^| findstr :${PORT}.*LISTENING') do taskkill /PID %a /F`
        : `  kill $(lsof -tnP -iTCP:${PORT} -sTCP:LISTEN)`);
      console.error("");
      console.error(t("console.stopFailedRetry"));
      process.exitCode = 1;
      return;
    }
    console.log(t("console.replaced"));
  }

  console.log(t("console.starting"));
  // server.js meldet einen belegten Port selbst mit klarem Text (siehe dort
  // den error-Zweig) — hier ist nichts abzufangen.
  require("./server.js");
}

main();
