import { createHmac } from "node:crypto";
import http from "node:http";
import { createAccessTokenVerifier, createSupersessionVerifier } from "@zaparo/k-identity/verify";
import { handleRoomsRequest } from "./router.js";
const MAX_BODY_BYTES = 256 * 1024;
const port = Number(process.env.ROOMS_PORT ?? 8830);
const issuer = process.env.K_ISSUER ?? "https://k.kbsoap.com/t/zaparo";
const verifyToken = createAccessTokenVerifier(issuer);
const supersede = createSupersessionVerifier(issuer);
const allowed = new Set((process.env.ROOMS_APP_IDS ?? "").split(",").map((id) => id.trim()).filter(Boolean));
if (allowed.size === 0)
    throw new Error("ROOMS_APP_IDS is not set");
const knownApps = async (appId) => allowed.has(appId);
const notifyBase = process.env.NOTIFY_BASE_URL ?? "https://bell.kbsoap.com";
const notifyTimeoutMs = Number(process.env.NOTIFY_TIMEOUT_MS ?? 3000);
const notifyKeys = JSON.parse(process.env.ROOMS_NOTIFY_KEYS ?? "{}");
const notify = async (event) => {
    const { app_id, ...rest } = event;
    const credential = notifyKeys[app_id];
    if (!credential)
        return;
    const rawBody = JSON.stringify(rest);
    const timestamp = Math.floor(Date.now() / 1000);
    const signature = createHmac("sha256", credential.secret)
        .update(`${credential.key_id}\n${timestamp}\n${rawBody}`, "utf8")
        .digest("hex");
    const response = await fetch(`${notifyBase}/notify/v1/emit`, {
        method: "POST",
        headers: {
            "content-type": "application/json",
            "x-notify-key": credential.key_id,
            "x-notify-timestamp": String(timestamp),
            "x-notify-signature": signature,
        },
        body: rawBody,
        signal: AbortSignal.timeout(notifyTimeoutMs),
    });
    if (!response.ok) {
        console.error(`[rooms] bell answered ${response.status} for ${event.category}`);
    }
};
const deps = { verifyToken, supersede, knownApps, notify };
const server = http.createServer(async (req, res) => {
    const url = new URL(req.url ?? "/", "http://localhost");
    let body = undefined;
    if (req.method !== "GET" && req.method !== "HEAD") {
        try {
            const raw = await readRaw(req, MAX_BODY_BYTES);
            const text = raw.toString("utf8");
            body = text.length > 0 ? JSON.parse(text) : undefined;
        }
        catch {
            res.writeHead(400, { "content-type": "application/json" });
            res.end(JSON.stringify({ error: { code: "invalid_json", message: "Body must be JSON" } }));
            return;
        }
    }
    const result = await handleRoomsRequest({
        method: req.method ?? "GET",
        path: url.pathname,
        header: (name) => header(req, name.toLowerCase()),
        body,
    }, deps);
    res.writeHead(result.status, { "content-type": result.contentType, "cache-control": "no-store" });
    res.end(result.body);
});
function header(req, name) {
    const value = req.headers[name];
    return Array.isArray(value) ? (value[0] ?? null) : (value ?? null);
}
function readRaw(req, limit) {
    return new Promise((resolve, reject) => {
        const chunks = [];
        let size = 0;
        req.on("data", (chunk) => {
            size += chunk.length;
            if (size > limit) {
                reject(new Error("body too large"));
                req.destroy();
                return;
            }
            chunks.push(chunk);
        });
        req.on("end", () => resolve(Buffer.concat(chunks)));
        req.on("error", reject);
    });
}
server.listen(port, "127.0.0.1", () => {
    console.log(`[rooms] listening on 127.0.0.1:${port}`);
});
