/**
 * Server initialization — preloaded via `node --require ./server-init.js server.js`
 *
 * Handles four concerns that the Next.js-generated server.js does not:
 *   1. mDNS bypass: wraps http.createServer to 302-redirect *.local to LAN IP
 *   2. systemd sd_notify: sends READY=1 on startup, WATCHDOG=1 every 15s
 *   3. Graceful shutdown: drains connections on SIGTERM before exit
 *   4. Startup logging
 *
 * Framework-agnostic — survives a Next.js replacement.
 */

'use strict'

const http = require('node:http')
const { spawnSync } = require('node:child_process')
const os = require('node:os')

// ---------------------------------------------------------------------------
// 1. mDNS bypass — redirect *.local to LAN IP
// ---------------------------------------------------------------------------

function getLanIp() {
  const nets = os.networkInterfaces()
  let fallback = null
  for (const entries of Object.values(nets)) {
    if (!entries) continue
    for (const entry of entries) {
      if (entry.family !== 'IPv4' || entry.internal) continue
      if (entry.address.startsWith('192.168.') || entry.address.startsWith('10.')) {
        return entry.address
      }
      if (!fallback) fallback = entry.address
    }
  }
  return fallback
}

// Paths that must NOT be redirected (API calls, static assets, VNC)
const SKIP_REDIRECT_RE = /^\/(api|assets|brand|novnc|vnc-viewer|vnc-popout|favicon)/

const _originalCreateServer = http.createServer.bind(http)

http.createServer = function patchedCreateServer(...args) {
  const requestListener = typeof args[0] === 'function' ? args[0] : args[1]
  const opts = typeof args[0] === 'function' ? undefined : args[0]
  function wrappedListener(req, res) {
    const host = req.headers.host || ''
    if (/^[a-z0-9-]+\.local(:|$)/.test(host) && !SKIP_REDIRECT_RE.test(req.url || '')) {
      const ip = getLanIp()
      if (ip) {
        const port = host.includes(':') ? host.split(':')[1] : '19200'
        res.writeHead(302, { Location: `http://${ip}:${port}${req.url || '/'}` })
        res.end()
        return
      }
    }
    requestListener(req, res)
  }
  return opts
    ? _originalCreateServer(opts, wrappedListener)
    : _originalCreateServer(wrappedListener)
}

console.error('[server-init] mDNS bypass active (*.local → LAN IP)')

// ---------------------------------------------------------------------------
// 2. systemd sd_notify via systemd-notify command
// ---------------------------------------------------------------------------

const NOTIFY_SOCKET = process.env.NOTIFY_SOCKET

function sdNotify(message) {
  if (!NOTIFY_SOCKET) return
  try {
    spawnSync('systemd-notify', [message], { stdio: 'pipe', timeout: 3000 })
  } catch { /* non-critical */ }
}

if (NOTIFY_SOCKET) {
  // Send READY=1 once the event loop is established (next tick after server.js loads)
  setImmediate(() => {
    sdNotify('--ready')
    console.error('[server-init] sd_notify READY=1 sent')
  })

  // Watchdog ping every 15s (WatchdogSec=30, ping at half-interval)
  const watchdogInterval = setInterval(() => sdNotify('WATCHDOG=1'), 15_000)
  watchdogInterval.unref() // don't keep the process alive for this
  console.error('[server-init] watchdog enabled (15s interval)')
} else {
  console.error('[server-init] no NOTIFY_SOCKET, watchdog disabled')
}

// ---------------------------------------------------------------------------
// 3. Graceful shutdown on SIGTERM
// ---------------------------------------------------------------------------

let shuttingDown = false

function gracefulShutdown(signal) {
  if (shuttingDown) return
  shuttingDown = true
  console.error(`[server-init] ${signal} received, shutting down...`)
  sdNotify('STOPPING=1\nSTATUS=Draining connections')

  // Give in-flight requests 5s to complete, then exit
  setTimeout(() => {
    console.error('[server-init] drain timeout, exiting')
    process.exit(0)
  }, 5_000).unref()
}

process.on('SIGTERM', () => gracefulShutdown('SIGTERM'))
process.on('SIGINT', () => gracefulShutdown('SIGINT'))
