/**
 * Hostinger Cloud entry-point — Option C (zero rewrite).
 *
 *   [Hostinger Node.js app :PORT]  (this process)
 *        │
 *        ├─ spawns:  python3 -m uvicorn server:app  @ 127.0.0.1:8001
 *        │
 *        ├─ /api/*   →  reverse-proxy to 127.0.0.1:8001  (FastAPI)
 *        │
 *        └─ /*       →  static files from frontend/dist  (SPA index.html fallback)
 *
 * Why Node in front of Python?
 *   • hPanel's "Setup Node.js app" flow only knows how to start Node.
 *     By wrapping uvicorn in a child process we get one unit that
 *     Hostinger can restart on git deploys, while keeping 100% of
 *     the existing FastAPI code unchanged.
 *   • Same process also serves the built SPA, so subscribers never
 *     hit a CORS pre-flight — /api and / are same-origin on nadi.kr.
 *
 * ENV variables to set in hPanel → Node.js app → "Environment variables":
 *   PORT                 (injected by hPanel; do not set manually)
 *   MONGO_URL            mongodb+srv://…   (MongoDB Atlas free tier works)
 *   DB_NAME              nadiplayer_db
 *   JWT_SECRET           production-grade random 64-char string
 *   FERNET_KEY           32-byte urlsafe-base64 (python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())")
 *   ADMIN_USERNAME       admin
 *   ADMIN_PASSWORD       <real admin password>
 *   CORS_ORIGINS         https://nadi.kr
 *   SUPABASE_URL         https://cojkdwpebofrczfjaxua.supabase.co
 *   SUPABASE_ANON_KEY    eyJ… (JWT anon key from Project Settings → API)
 *   SUPABASE_SERVICE_KEY eyJ… (service_role key — SERVER ONLY, never in frontend)
 *   PYTHON_BIN           (optional) /usr/bin/python3.11 — leave unset if `python3` is on PATH
 */

const express = require("express");
const path = require("path");
const fs = require("fs");
const { spawn } = require("child_process");
const { createProxyMiddleware } = require("http-proxy-middleware");
const { createClient } = require("@supabase/supabase-js");

// ─────────────────────────────────────────────────────────────
// Config
// ─────────────────────────────────────────────────────────────
const PORT = parseInt(process.env.PORT || "3000", 10);
const PY_PORT = parseInt(process.env.PY_PORT || "8001", 10);
const PY_HOST = "127.0.0.1";
const PYTHON_BIN = process.env.PYTHON_BIN || "python3";
const BACKEND_DIR = path.join(__dirname, "backend");
const SPA_DIR = path.join(__dirname, "frontend", "dist");

// ─────────────────────────────────────────────────────────────
// Supabase client — exposed on `app.locals.supabase` in case we
// add endpoints later. Safe to initialise even if keys are missing
// (we just skip it and log a warning).
// ─────────────────────────────────────────────────────────────
let supabase = null;
if (process.env.SUPABASE_URL && process.env.SUPABASE_SERVICE_KEY) {
  supabase = createClient(
    process.env.SUPABASE_URL,
    process.env.SUPABASE_SERVICE_KEY,
    { auth: { persistSession: false } },
  );
  console.log("[hostinger] Supabase client ready →", process.env.SUPABASE_URL);
} else if (process.env.SUPABASE_URL && process.env.SUPABASE_ANON_KEY) {
  supabase = createClient(process.env.SUPABASE_URL, process.env.SUPABASE_ANON_KEY);
  console.log("[hostinger] Supabase client ready (anon) →", process.env.SUPABASE_URL);
} else {
  console.log("[hostinger] Supabase disabled (SUPABASE_URL / key not set)");
}

// ─────────────────────────────────────────────────────────────
// Spawn FastAPI (uvicorn)
// ─────────────────────────────────────────────────────────────
function spawnPython() {
  console.log(
    `[hostinger] spawning ${PYTHON_BIN} -m uvicorn server:app @ ${PY_HOST}:${PY_PORT}`,
  );
  const child = spawn(
    PYTHON_BIN,
    [
      "-m",
      "uvicorn",
      "server:app",
      "--host",
      PY_HOST,
      "--port",
      String(PY_PORT),
      "--proxy-headers",
      "--forwarded-allow-ips",
      "*",
    ],
    {
      cwd: BACKEND_DIR,
      stdio: "inherit",
      env: { ...process.env, PYTHONUNBUFFERED: "1" },
    },
  );
  child.on("exit", (code, signal) => {
    console.error(`[hostinger] uvicorn exited  code=${code}  signal=${signal}`);
    // If uvicorn dies we want the Node process to exit so hPanel
    // restarts the whole unit (systemd-style supervision).
    process.exit(code == null ? 1 : code);
  });
  return child;
}
const py = spawnPython();

// Forward SIGTERM/SIGINT so Ctrl-C or hPanel restart cleanly kills both.
["SIGTERM", "SIGINT"].forEach((sig) => {
  process.on(sig, () => {
    try { py.kill(sig); } catch (_e) { /* noop */ }
  });
});

// ─────────────────────────────────────────────────────────────
// Express app
// ─────────────────────────────────────────────────────────────
const app = express();
app.disable("x-powered-by");
app.set("trust proxy", true); // we sit behind Hostinger's TLS terminator
app.locals.supabase = supabase;

// Tiny liveness probe — lets hPanel show "healthy" and lets us smoke-test
// the Node layer in isolation without hitting Python.
app.get("/__hostinger/health", (_req, res) => {
  res.json({
    ok: true,
    node_port: PORT,
    python_port: PY_PORT,
    supabase: !!supabase,
    ts: new Date().toISOString(),
  });
});

// Reverse-proxy /api → FastAPI. We keep the /api prefix intact so the
// Python side (which also uses /api prefix) matches routes as before.
app.use(
  "/api",
  createProxyMiddleware({
    target: `http://${PY_HOST}:${PY_PORT}`,
    changeOrigin: false, // keep original Host so admin CORS works
    ws: false,
    xfwd: true,
    timeout: 60_000,       // 60s — generous for upstream IPTV fetches
    proxyTimeout: 60_000,
    pathRewrite: (p) => `/api${p}`, // /api/foo arrives here as /foo → send /api/foo
    onError(err, _req, res) {
      console.error("[hostinger] proxy error:", err.message);
      if (!res.headersSent) {
        res.status(502).json({
          error: "backend unavailable",
          detail: err.message,
          hint: "check hPanel logs; FastAPI child may have crashed",
        });
      }
    },
  }),
);

// Static SPA — served ONLY if frontend/dist exists (the hPanel-deployed
// frontend may be served from a different vhost; in that case these
// lines are no-ops).
if (fs.existsSync(SPA_DIR)) {
  console.log("[hostinger] serving SPA from", SPA_DIR);
  app.use(express.static(SPA_DIR, { maxAge: "1h", index: false }));
  app.get("*", (_req, res) => {
    res.sendFile(path.join(SPA_DIR, "index.html"));
  });
} else {
  console.log("[hostinger] no frontend/dist found — API-only mode");
  app.get("/", (_req, res) =>
    res.type("text").send("Nadiplayer API (Node+FastAPI). GET /api/ to probe."),
  );
}

// ─────────────────────────────────────────────────────────────
// Listen
// ─────────────────────────────────────────────────────────────
app.listen(PORT, () => {
  console.log(`[hostinger] Express listening on :${PORT}`);
});
