/**
 * @file Tests the DASHBOARD_CLIENT_DIST override in server/index.js. A plugin
 * install runs the server from a read-only plugin cache directory, so the
 * client bundle is served from the writable runtime dir instead of the
 * checkout's client/dist. Also asserts the API still answers when the
 * configured bundle directory does not exist yet (the normal state before
 * /ccam-open builds it).
 * @author Nguyễn Ngọc Trí Vĩ <vinnt@smartgift.vn>
 */

const { describe, it, before, after } = require("node:test");
const assert = require("node:assert/strict");
const fs = require("fs");
const os = require("os");
const path = require("path");
const http = require("http");

const TMP = fs.mkdtempSync(path.join(os.tmpdir(), "ccam-clientdist-"));
const DIST = path.join(TMP, "client-dist");
fs.mkdirSync(DIST);
fs.writeFileSync(path.join(DIST, "index.html"), "<!doctype html><title>from-runtime</title>");

// Must be set BEFORE requiring the server: the data dir, discovery file and
// the static mount are all resolved at startup.
process.env.CLAUDE_HOME = TMP;
process.env.DASHBOARD_DB_PATH = path.join(TMP, "test.db");
process.env.DASHBOARD_LIVENESS_PROBE = "0";
process.env.DASHBOARD_CLIENT_DIST = DIST;

const { createApp, startServer } = require("../index");
const { db } = require("../db");

let server;
let BASE;

function get(urlPath) {
  return new Promise((resolve, reject) => {
    const req = http.get(new URL(urlPath, BASE), (res) => {
      let body = "";
      res.on("data", (c) => (body += c));
      res.on("end", () => resolve({ status: res.statusCode, body }));
    });
    req.on("error", reject);
  });
}

describe("DASHBOARD_CLIENT_DIST override", () => {
  before(async () => {
    server = await startServer(createApp(), 0);
    BASE = `http://127.0.0.1:${server.address().port}`;
  });

  after(() => {
    if (server) server.close();
    if (db) db.close();
    fs.rmSync(TMP, { recursive: true, force: true });
    delete process.env.DASHBOARD_CLIENT_DIST;
  });

  it("serves index.html from the configured directory", async () => {
    const res = await get("/");
    assert.equal(res.status, 200);
    assert.match(res.body, /from-runtime/);
  });

  it("keeps the API working alongside the override", async () => {
    const res = await get("/api/health");
    assert.equal(res.status, 200);
  });
});

describe("DASHBOARD_CLIENT_DIST pointing at a missing directory", () => {
  let srv;
  let base;

  before(async () => {
    process.env.DASHBOARD_CLIENT_DIST = path.join(TMP, "not-built-yet");
    srv = await startServer(createApp(), 0);
    base = `http://127.0.0.1:${srv.address().port}`;
  });

  after(() => {
    if (srv) srv.close();
  });

  it("answers the API and only 404s the UI route", async () => {
    const prevBase = BASE;
    BASE = base;
    try {
      const health = await get("/api/health");
      assert.equal(health.status, 200);
      const ui = await get("/");
      assert.equal(ui.status, 404);
    } finally {
      BASE = prevBase;
    }
  });
});
