/**
 * startup.ts — TypeScript equivalent of startup.sh
 *
 * Normalizes DB paths, starts the bot (index.ts) and web app (SvelteKit)
 * in the background, waits for the database and auth tables to be ready,
 * then runs the proxy router in the foreground.
 */

import { existsSync } from "node:fs";
import { resolve } from "node:path";

// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------

/** Track spawned children so we can clean them up on exit. */
const children: { proc: ReturnType<typeof Bun.spawn> }[] = [];

function cleanup(): void {
  for (const { proc } of children) {
    try {
      proc.kill();
    } catch {
      // Process already dead – ignore
    }
  }
}

process.on("SIGTERM", () => {
  cleanup();
  process.exit(0);
});
process.on("SIGINT", () => {
  cleanup();
  process.exit(0);
});

// ---------------------------------------------------------------------------
// 1. Normalize DB paths to absolute (readlink -f equivalent)
// ---------------------------------------------------------------------------

let dbPath = process.env.DB_PATH;
let dataDir = process.env.DATA_DIR || "/app/data";

if (dbPath) {
  try {
    dbPath = resolve(dbPath);
    process.env.DB_PATH = dbPath;
  } catch {
    // Equivalent to `readlink -f "$DB_PATH" || true`
  }
} else {
  try {
    dataDir = resolve(dataDir);
    process.env.DATA_DIR = dataDir;
  } catch {
    // Equivalent to `readlink -f "$DATA_DIR" || true`
  }
}

// ---------------------------------------------------------------------------
// 2. Determine the DB file path for wait checks
// ---------------------------------------------------------------------------

const dbFile: string = process.env.DB_PATH
  ? process.env.DB_PATH
  : `${process.env.DATA_DIR || "/app/data"}/tasks.db`;

// ---------------------------------------------------------------------------
// 3. Start the bot in the background (default port 3007)
// ---------------------------------------------------------------------------

const botPort = process.env.BOT_PORT || "3007";
const botProc = Bun.spawn({
  cmd: ["bun", "run", "index.ts"],
  env: { ...process.env, PORT: botPort },
  stdout: "inherit",
  stderr: "inherit",
});
children.push({ proc: botProc });

// ---------------------------------------------------------------------------
// 4. Wait for the DB file to exist (max ~30 s)
// ---------------------------------------------------------------------------

console.log(`[startup] Waiting for database at: ${dbFile}`);
for (let i = 0; i < 150; i++) {
  if (existsSync(dbFile)) break;
  await Bun.sleep(200);
}

// ---------------------------------------------------------------------------
// 5. Wait for auth tables (web_tokens, web_sessions) — max ~30 s
// ---------------------------------------------------------------------------

// Check if sqlite3 CLI is available (equivalent to `command -v sqlite3`)
let hasSqlite3 = false;
try {
  const check = Bun.spawn({
    cmd: ["sqlite3", "--version"],
    stdout: "pipe",
    stderr: "pipe",
  });
  await check.exited;
  hasSqlite3 = check.exitCode === 0;
} catch {
  hasSqlite3 = false;
}

if (hasSqlite3) {
  console.log(
    "[startup] Checking for auth tables (web_tokens, web_sessions)...",
  );
  let authReady = false;
  for (let i = 0; i < 150; i++) {
    if (existsSync(dbFile)) {
      const proc = Bun.spawn({
        cmd: [
          "sqlite3",
          dbFile,
          "SELECT 1 FROM sqlite_master WHERE type='table' AND name IN ('web_tokens','web_sessions') LIMIT 1;",
        ],
        stdout: "pipe",
        stderr: "pipe",
      });
      const out = await new Response(proc.stdout).text();
      await proc.exited;
      if (out.trim() === "1") {
        authReady = true;
        break;
      }
    }
    await Bun.sleep(200);
  }
  if (!authReady) {
    console.log(
      "[startup] Warning: auth tables may not be ready after waiting.",
    );
  }
} else {
  console.log(
    "[startup] sqlite3 not available; skipping auth-table verification (continuing).",
  );
}

// ---------------------------------------------------------------------------
// 6. Start the web app (SvelteKit) in the background (default port 3008)
// ---------------------------------------------------------------------------

const webPort = process.env.WEB_PORT || "3008";
const webProc = Bun.spawn({
  cmd: ["bun", "./build/index.js"],
  cwd: resolve("apps/web"),
  env: { ...process.env, PORT: webPort },
  stdout: "inherit",
  stderr: "inherit",
});
children.push({ proc: webProc });

// ---------------------------------------------------------------------------
// 7. Small wait to avoid race conditions
// ---------------------------------------------------------------------------

await Bun.sleep(1000);

// ---------------------------------------------------------------------------
// 8. Start the proxy router in the foreground (default port 3000)
// ---------------------------------------------------------------------------

const port = process.env.PORT || "3000";
const proxyProc = Bun.spawn({
  cmd: ["bun", "proxy.ts"],
  env: { ...process.env, PORT: port },
  stdout: "inherit",
  stderr: "inherit",
});

// Wait for the proxy (foreground process) to exit, then shut down.
const exitCode = await proxyProc.exited;
console.log(`[startup] Proxy exited with code ${exitCode}`);

cleanup();
process.exit(typeof exitCode === "number" ? exitCode : 1);
