/**
 * Occupancy: the refusal, the ordering that makes it safe, and the file.
 *
 * Two assertions carry this file and both are negative.
 *
 * The first is the refusal itself. Before this route, `member` and `anon`
 * differed *inside the office* only in the browser: the client picked a depth
 * and the server never refused anybody anything. `markers.test.ts` makes the
 * same argument for the city and it is the same argument — a tier drawn in the
 * client is a UI hiding a control over a body the API hands to whoever asks.
 *
 * The second is the ordering, and it is the subtler one. CONTRACT.md §6 forbids
 * an endpoint that lets the id space be walked for a tenant list. This route
 * resolves the viewer before it looks at the id, so an anonymous caller gets an
 * identical 401 for a real office, a private one and one that was never created.
 * Check the office first and the status codes tell them apart perfectly, which
 * is the enumeration oracle wearing a different number. The test for that is
 * three requests and one `deepEqual`.
 *
 * Follows `offices.test.ts`: a temp directory, `buildApp` over a fake
 * environment, `inject()` rather than a socket, and HS256 by hand.
 */

import assert from "node:assert/strict";
import { createHmac } from "node:crypto";
import { mkdtemp, writeFile } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { after, before, describe, it } from "node:test";
import { buildApp } from "../app.ts";
import { loadConfig } from "../config.ts";
import type { PresenceBody } from "../../../src/server/wire.ts";

const SECRET = "not-a-real-secret-and-never-was";

/** A minimal floor. `Plan` is what makes sense of it; the API only carries it. */
const floor = { id: "hq", name: "HQ", levels: [], viewpoints: [] };

let offices = "";
let presence = "";

before(async () => {
  offices = await mkdtemp(join(tmpdir(), "tera-offices-"));
  presence = await mkdtemp(join(tmpdir(), "tera-presence-"));

  await writeFile(
    join(offices, "open.json"),
    JSON.stringify({ id: "open", name: "Open office", visibility: "public", floor }),
  );
  await writeFile(
    join(offices, "closed.json"),
    JSON.stringify({ id: "closed", name: "Closed office", visibility: "private", floor }),
  );
  // An office with no roster beside it. Deliberately: "no such office" and
  // "nobody has told me who is in this one" are different facts.
  await writeFile(
    join(offices, "empty.json"),
    JSON.stringify({ id: "empty", name: "Empty office", visibility: "public", floor }),
  );

  await writeFile(
    join(presence, "open.json"),
    JSON.stringify({
      observedAt: "2026-08-06T09:00:00.000Z",
      people: [
        { id: "p-01", seatId: "eng-01", label: "Tobias Quillon", colorKey: "in" },
        { id: "p-02", seatId: "eng-02", label: "Ines Marchetti", colorKey: "focus" },
        // No id: the seat stands in for one, because a roster listing one desk
        // twice is a mistake in the file and not two people.
        { seatId: "eng-03", label: "Dara Oyelaran-Pike" },
        // No seat: unplaceable, and dropped rather than repaired. Inventing a
        // desk would turn a private id into a public coordinate.
        { id: "p-04", label: "Nobody In Particular" },
        "not even an object",
      ],
    }),
  );
  await writeFile(join(presence, "closed.json"), JSON.stringify({ people: [] }));
  await writeFile(join(presence, "broken.json"), "{ this is not json");
});

function appWith(env: Record<string, string>) {
  const config = loadConfig({
    TERA_OFFICES_DIR: offices,
    TERA_PRESENCE_DIR: presence,
    ...env,
  });
  config.logLevel = "silent";
  return buildApp(config);
}

function hs256(claims: Record<string, unknown>): string {
  const encode = (value: unknown): string =>
    Buffer.from(JSON.stringify(value)).toString("base64url");
  const signed = `${encode({ alg: "HS256", typ: "JWT" })}.${encode(claims)}`;
  return `${signed}.${createHmac("sha256", SECRET).update(signed).digest("base64url")}`;
}

const jwt = { TERA_AUTH_MODE: "jwt", TERA_AUTH_JWT_SECRET: SECRET };

function bearer(): { authorization: string } {
  return { authorization: `Bearer ${hs256({ sub: "someone", exp: nextHour() })}` };
}

/**
 * An hour out, computed rather than written down: a fixed `exp` in a test file
 * is a test that starts failing on a date nobody chose.
 */
function nextHour(): number {
  return Math.floor(Date.now() / 1000) + 3600;
}

describe("the refusal", () => {
  it("refuses an anonymous caller even for a public office", async () => {
    const app = appWith(jwt);
    after(() => app.close());

    const res = await app.inject({ method: "GET", url: "/api/v1/offices/open/presence" });
    assert.equal(res.statusCode, 401);
    assert.equal(res.headers["www-authenticate"], "Bearer");
    // The point: the office itself is public and readable by this same caller.
    const doc = await app.inject({ method: "GET", url: "/api/v1/offices/open" });
    assert.equal(doc.statusCode, 200);
  });

  it("tells a real, a private and an absent office apart for nobody", async () => {
    const app = appWith(jwt);
    after(() => app.close());

    const real = await app.inject({ method: "GET", url: "/api/v1/offices/open/presence" });
    const priv = await app.inject({ method: "GET", url: "/api/v1/offices/closed/presence" });
    const gone = await app.inject({ method: "GET", url: "/api/v1/offices/no-such-thing/presence" });

    assert.equal(real.statusCode, 401);
    assert.equal(priv.statusCode, 401);
    assert.equal(gone.statusCode, 401);
    assert.deepEqual(real.json(), priv.json());
    assert.deepEqual(real.json(), gone.json());
  });

  it("never lets a shared cache keep a roster", async () => {
    const app = appWith(jwt);
    after(() => app.close());

    const res = await app.inject({
      method: "GET",
      url: "/api/v1/offices/open/presence",
      headers: bearer(),
    });
    assert.equal(res.statusCode, 200);
    assert.equal(res.headers["cache-control"], "private, no-store");
  });

  it("is unreachable by everyone when nobody can sign in", async () => {
    // `TERA_AUTH_MODE=none` means no caller is ever authenticated, so this route
    // refuses the whole world. That is the fail-closed direction and the same one
    // a private office already takes.
    const app = appWith({});
    after(() => app.close());

    const res = await app.inject({
      method: "GET",
      url: "/api/v1/offices/open/presence",
      headers: bearer(),
    });
    assert.equal(res.statusCode, 401);
  });
});

describe("the file", () => {
  it("serves the roster to a signed-in caller", async () => {
    const app = appWith(jwt);
    after(() => app.close());

    const res = await app.inject({
      method: "GET",
      url: "/api/v1/offices/open/presence",
      headers: bearer(),
    });
    assert.equal(res.statusCode, 200);
    const body = res.json<PresenceBody>();
    assert.equal(body.officeId, "open");
    assert.equal(body.observedAt, "2026-08-06T09:00:00.000Z");
    assert.deepEqual(
      body.people.map((p) => p.seatId),
      ["eng-01", "eng-02", "eng-03"],
    );
  });

  it("drops the unplaceable and keeps the rest of the file", async () => {
    const app = appWith(jwt);
    after(() => app.close());

    const body = (
      await app.inject({
        method: "GET",
        url: "/api/v1/offices/open/presence",
        headers: bearer(),
      })
    ).json<PresenceBody>();

    // A row with no seat and a row that is not an object are both gone, and
    // neither took the three good rows with it.
    assert.equal(body.people.length, 3);
    assert.ok(!body.people.some((p) => p.label === "Nobody In Particular"));
  });

  it("stands the seat in for a missing id and defaults the colour", async () => {
    const app = appWith(jwt);
    after(() => app.close());

    const body = (
      await app.inject({
        method: "GET",
        url: "/api/v1/offices/open/presence",
        headers: bearer(),
      })
    ).json<PresenceBody>();

    const third = body.people[2];
    assert.equal(third?.id, "eng-03");
    assert.equal(third?.colorKey, "in");
  });

  it("answers 200 and an empty list for an office with no roster", async () => {
    // Not 404. An unset roster is a different problem from a wrong URL, and
    // sending an operator looking for the wrong one costs them an afternoon.
    const app = appWith(jwt);
    after(() => app.close());

    const res = await app.inject({
      method: "GET",
      url: "/api/v1/offices/empty/presence",
      headers: bearer(),
    });
    assert.equal(res.statusCode, 200);
    assert.deepEqual(res.json<PresenceBody>().people, []);
  });

  it("answers 404 to a signed-in caller for an office that is not there", async () => {
    const app = appWith(jwt);
    after(() => app.close());

    const res = await app.inject({
      method: "GET",
      url: "/api/v1/offices/no-such-thing/presence",
      headers: bearer(),
    });
    assert.equal(res.statusCode, 404);
  });

  it("treats an unreadable roster as an empty one", async () => {
    // `broken.json` is not JSON. The building still renders; it renders empty.
    const app = appWith(jwt);
    after(() => app.close());

    await writeFile(
      join(offices, "broken.json"),
      JSON.stringify({ id: "broken", name: "Broken", visibility: "public", floor }),
    );

    const res = await app.inject({
      method: "GET",
      url: "/api/v1/offices/broken/presence",
      headers: bearer(),
    });
    assert.equal(res.statusCode, 200);
    assert.deepEqual(res.json<PresenceBody>().people, []);
  });

  it("has no people at all when no presence directory is configured", async () => {
    const config = loadConfig({ TERA_OFFICES_DIR: offices, ...jwt });
    config.logLevel = "silent";
    const app = buildApp(config);
    after(() => app.close());

    const res = await app.inject({
      method: "GET",
      url: "/api/v1/offices/open/presence",
      headers: bearer(),
    });
    assert.equal(res.statusCode, 200);
    assert.deepEqual(res.json<PresenceBody>().people, []);
  });
});

/**
 * The route that could not succeed in production.
 *
 * `routes/devices.ts` falls back to `bundledOffice` and this route did not, so on
 * a deployment that sets no `TERA_OFFICES_DIR` — which is the reference
 * deployment, and every clone — `offices.get()` answered `null` for every studio
 * the browser was actually standing in, and a signed-in member got a 404 from the
 * one route that exists to make signing in mean something. Presence was
 * unreachable in production for every pack, for every member.
 *
 * A bundled pack is not a leak here for exactly the reason `bundledOffice` gives:
 * it is compiled into the browser bundle that made the request, so its floorplan
 * is already in the caller's hands. The roster is a separate document and stays
 * behind `TERA_PRESENCE_DIR`, which is what keeps the geometry public and the
 * people not.
 */
describe("a bundled pack, which is what production actually serves", () => {
  it("answers a signed-in member for a pack no directory was configured for", async () => {
    const config = loadConfig(jwt);
    config.logLevel = "silent";
    const app = buildApp(config);
    after(() => app.close());

    const res = await app.inject({
      method: "GET",
      url: "/api/v1/offices/mateo-court/presence",
      headers: bearer(),
    });
    assert.equal(res.statusCode, 200);
    // Empty, not 404. "This office does not exist" and "nobody has told me who
    // is in this office" are different facts with different fixes.
    assert.deepEqual(res.json<PresenceBody>().people, []);
  });

  it("still refuses an anonymous caller, bundled or not", async () => {
    const config = loadConfig(jwt);
    config.logLevel = "silent";
    const app = buildApp(config);
    after(() => app.close());

    const res = await app.inject({ method: "GET", url: "/api/v1/offices/mateo-court/presence" });
    assert.equal(res.statusCode, 401);
  });

  it("still 404s an office that is neither served nor bundled", async () => {
    const config = loadConfig(jwt);
    config.logLevel = "silent";
    const app = buildApp(config);
    after(() => app.close());

    const res = await app.inject({
      method: "GET",
      url: "/api/v1/offices/not-a-place/presence",
      headers: bearer(),
    });
    assert.equal(res.statusCode, 404);
  });
});
