// S.O.L.O. WorkManager Launcher v1.0.68
// Sucht einen sicheren lokalen Port, erkennt alte/stale Server und oeffnet die passende App.
// Keine Prozess-Beendigung, keine Admin-Rechte, keine Windows-Shell.

const { spawn } = require('child_process');
const http = require('http');
const net = require('net');
const path = require('path');

const APP_VERSION = '1.0.68';
const APP_DIR = __dirname;
const APP_ROOT = process.argv[3] ? path.resolve(process.argv[3]) : path.resolve(path.join(APP_DIR, '..'));
const DIST_DIR = process.argv[2] || path.join(APP_DIR, 'dist');
const MIN_PORT = 53100;
const MAX_PORT = 53199;
const HEALTH_TIMEOUT_MS = 700;

function norm(p) {
  return path.resolve(String(p || '')).replace(/\\/g, '/').toLowerCase();
}

function httpGetJson(host, port, route) {
  return new Promise((resolve) => {
    const req = http.get({ hostname: host, port, path: route, timeout: HEALTH_TIMEOUT_MS }, (res) => {
      let body = '';
      res.on('data', (chunk) => { body += chunk; if (body.length > 64000) req.destroy(); });
      res.on('end', () => {
        try { resolve({ ok: true, status: res.statusCode, json: JSON.parse(body || '{}'), body }); }
        catch (e) { resolve({ ok: true, status: res.statusCode, json: null, body }); }
      });
    });
    req.on('timeout', () => { req.destroy(); resolve({ ok: false, error: 'timeout' }); });
    req.on('error', (err) => resolve({ ok: false, error: err.message }));
  });
}

async function probeExistingServer(port) {
  const hosts = ['localhost', '127.0.0.1'];
  for (const host of hosts) {
    const health = await httpGetJson(host, port, '/health');
    if (health.ok && health.json && health.json.app === 'SOLO_WORKMANAGER') {
      return { type: 'health', host, port, health: health.json };
    }
    const ping = await httpGetJson(host, port, '/ping');
    if (ping.ok) {
      return { type: 'occupied-http', host, port, health: health.json || null };
    }
  }
  return null;
}

function isHostPortFree(port, host) {
  return new Promise((resolve) => {
    const srv = net.createServer();
    srv.once('error', () => resolve(false));
    srv.once('listening', () => srv.close(() => resolve(true)));
    try { srv.listen(port, host); }
    catch (e) { resolve(false); }
  });
}

async function isPortFreeEverywhere(port) {
  const checks = [await isHostPortFree(port, '127.0.0.1')];
  try { checks.push(await isHostPortFree(port, '::1')); } catch (e) {}
  try { checks.push(await isHostPortFree(port, 'localhost')); } catch (e) {}
  return checks.every(Boolean);
}

async function findLaunchTarget() {
  for (let port = MIN_PORT; port <= MAX_PORT; port++) {
    const existing = await probeExistingServer(port);
    if (existing && existing.type === 'health') {
      const sameApp = norm(existing.health.appDir) === norm(APP_DIR) && norm(existing.health.dist) === norm(DIST_DIR) && existing.health.distOk === true;
      if (sameApp) {
        return { reuse: true, port, host: existing.host, url: 'http://localhost:' + port + '/' };
      }
      // A different or stale S.O.L.O. server is using this port. Do not open it.
      continue;
    }
    if (existing) {
      // Some HTTP server is responding here (possibly an older S.O.L.O. release without /health). Skip it.
      continue;
    }
    if (await isPortFreeEverywhere(port)) return { reuse: false, port, host: 'localhost', url: 'http://localhost:' + port + '/' };
  }
  throw new Error('Kein freier lokaler Port im Bereich ' + MIN_PORT + '-' + MAX_PORT + ' gefunden. Bitte alte S.O.L.O.-/node.exe-Prozesse schließen und erneut starten.');
}

function openBrowser(url) {
  try {
    const browser = spawn('explorer.exe', [url], { detached: true, windowsHide: true, stdio: 'ignore' });
    browser.unref();
  } catch (e) {
    console.log('[S.O.L.O. WorkManager] Bitte manuell im Browser oeffnen: ' + url);
  }
}

async function waitForHealth(port, attempts) {
  for (let i = 0; i < attempts; i++) {
    const health = await httpGetJson('localhost', port, '/health');
    if (health.ok && health.json && health.json.app === 'SOLO_WORKMANAGER' && health.json.distOk === true && norm(health.json.appDir) === norm(APP_DIR)) {
      return true;
    }
    await new Promise((resolve) => setTimeout(resolve, 250));
  }
  return false;
}

(async function main() {
  const target = await findLaunchTarget();
  if (target.reuse) {
    openBrowser(target.url);
    return;
  }

  const child = spawn(process.execPath, [
    path.join(APP_DIR, 'server.js'), String(target.port), DIST_DIR, APP_ROOT
  ], {
    detached: true,
    windowsHide: true,
    stdio: 'ignore'
  });
  child.unref();

  const ready = await waitForHealth(target.port, 60);
  if (!ready) throw new Error('Lokaler Server wurde gestartet, meldet aber keine gültige S.O.L.O.-Health-Antwort. Bitte ZIP neu entpacken und ueber START - S.O.L.O. WorkManager.bat starten.');
  openBrowser(target.url);
})().catch(function(err) {
  console.error('[S.O.L.O. WorkManager] Start fehlgeschlagen: ' + err.message);
  process.exit(1);
});
