import http from "node:http";
import { createAccessTokenVerifier, createSupersessionVerifier } from "@zaparo/k-identity/verify";
import { pushDirectory } from "./devices.js";
import { startNotifyDrain } from "./drain.js";
import { parseAppFamilies, setAppFamilies, setKnownApps } from "./registry.js";
import { handleNotifyRequest } from "./router.js";
const MAX_BODY_BYTES = 256 * 1024;
const port = Number(process.env.NOTIFY_PORT ?? 8824);
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.NOTIFY_APP_IDS ?? "").split(",").map((id) => id.trim()).filter(Boolean));
if (allowed.size === 0)
    throw new Error("NOTIFY_APP_IDS is not set");
setKnownApps(async (appId) => allowed.has(appId));
const families = parseAppFamilies(process.env.NOTIFY_APP_FAMILIES ?? "");
for (const [alias, root] of families) {
    if (!allowed.has(root)) {
        throw new Error(`NOTIFY_APP_FAMILIES: ${alias} names ${root}, which is not in NOTIFY_APP_IDS`);
    }
}
setAppFamilies(families);
const deps = { verifyToken, supersede };
const server = http.createServer(async (req, res) => {
    const url = new URL(req.url ?? "/", "http://localhost");
    let body = undefined;
    let rawBody = undefined;
    if (req.method !== "GET" && req.method !== "HEAD") {
        try {
            rawBody = (await readRaw(req, MAX_BODY_BYTES)).toString("utf8");
            body = rawBody.length > 0 ? JSON.parse(rawBody) : undefined;
        }
        catch {
            body = undefined;
        }
    }
    const result = await handleNotifyRequest({
        method: req.method ?? "GET",
        path: url.pathname,
        header: (name) => {
            const value = req.headers[name.toLowerCase()];
            return Array.isArray(value) ? (value[0] ?? null) : (value ?? null);
        },
        body,
        rawBody,
    }, deps);
    res.writeHead(result.status, { "content-type": result.contentType, "cache-control": "no-store" });
    res.end(result.body);
});
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", () => {
    startNotifyDrain(pushDirectory);
    console.log(`[notify] listening on 127.0.0.1:${port}`);
});
