/**
 * webhook-server.ts
 *
 * Local development server for testing the webhook handler.
 *
 * Starts an HTTP server that receives Sanity webhook payloads, processes
 * them through the WebhookHandler, and logs results. Useful for local
 * development and testing the full event-driven trigger flow.
 *
 * Migrated from lib/webhook-server.ts — accepts rootDir and port as parameters.
 *
 * @see docs/design-docs/report-store/visibility-workflows.md
 */
import { createServer } from "http";
import { allTrackedSlugs, buildReverseMapping } from "./reverse-mapping.js";
import { WebhookHandler } from "../webhook/handler.js";
// ---------------------------------------------------------------------------
// Server
// ---------------------------------------------------------------------------
/**
 * Start the webhook development server.
 *
 * This function blocks and keeps the process alive.
 * Returns the HTTP server instance for graceful shutdown in tests.
 */
export function startWebhookServer(options) {
    const { rootDir, port = 3333, githubToken = "", dailyBudget = 20, debounceMs = 10000, } = options;
    const DRY_RUN = !githubToken;
    const handler = new WebhookHandler({
        dailyBudget,
        debounceMs,
        githubToken,
        rootDir,
    });
    const server = createServer((req, res) => {
        void handleRequest(req, res, { handler, rootDir, port, DRY_RUN });
    });
    server.listen(port, () => {
        const reverseMapping = buildReverseMapping(rootDir);
        const slugCount = allTrackedSlugs(reverseMapping).length;
        console.log();
        console.log("=== AILF Webhook Server ===");
        console.log();
        console.log(`  Port:           ${port}`);
        console.log(`  Mode:           ${DRY_RUN ? "DRY RUN (set GITHUB_TOKEN to dispatch)" : "LIVE"}`);
        console.log(`  Tracked slugs:  ${slugCount}`);
        console.log(`  Debounce:       ${handler.diagnostics().pendingSlugs}`);
        console.log();
        console.log("  Endpoints:");
        console.log(`    POST http://localhost:${port}/webhook   — handle webhook`);
        console.log(`    GET  http://localhost:${port}/health    — diagnostics`);
        console.log(`    GET  http://localhost:${port}/mappings  — slug → area map`);
        console.log();
    });
    // Graceful shutdown
    process.on("SIGINT", () => {
        console.log("\n  Shutting down — flushing debounce window...");
        void handler.shutdown().then(() => {
            server.close();
            process.exit(0);
        });
    });
    return { server, handler };
}
// ---------------------------------------------------------------------------
// Request handler
// ---------------------------------------------------------------------------
async function handleRequest(req, res, ctx) {
    const url = new URL(req.url ?? "/", `http://localhost:${ctx.port}`);
    // CORS headers for local dev
    res.setHeader("Access-Control-Allow-Origin", "*");
    res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
    res.setHeader("Access-Control-Allow-Headers", "Content-Type");
    if (req.method === "OPTIONS") {
        res.writeHead(200);
        res.end();
        return;
    }
    // Health check
    if (url.pathname === "/health" && req.method === "GET") {
        const diagnostics = ctx.handler.diagnostics();
        res.writeHead(200, { "Content-Type": "application/json" });
        res.end(JSON.stringify({ dryRun: ctx.DRY_RUN, ...diagnostics }, null, 2));
        return;
    }
    // Mappings
    if (url.pathname === "/mappings" && req.method === "GET") {
        const reverseMapping = buildReverseMapping(ctx.rootDir);
        const slugs = allTrackedSlugs(reverseMapping);
        const mappings = Object.fromEntries(slugs.map((slug) => [slug, reverseMapping.get(slug)]));
        res.writeHead(200, { "Content-Type": "application/json" });
        res.end(JSON.stringify({ mappings, slugCount: slugs.length }, null, 2));
        return;
    }
    // Webhook handler
    if (url.pathname === "/webhook" && req.method === "POST") {
        const body = await readBody(req);
        let payload;
        try {
            payload = JSON.parse(body);
        }
        catch {
            res.writeHead(400, { "Content-Type": "application/json" });
            res.end(JSON.stringify({ error: "Invalid JSON" }));
            return;
        }
        if (ctx.DRY_RUN) {
            console.log("\n  🔶 DRY RUN — would dispatch (no GITHUB_TOKEN set)");
        }
        const result = ctx.handler.handle(payload);
        console.log(`  → ${result.status}:`, JSON.stringify(result));
        res.writeHead(200, { "Content-Type": "application/json" });
        res.end(JSON.stringify(result, null, 2));
        return;
    }
    // 404
    res.writeHead(404, { "Content-Type": "application/json" });
    res.end(JSON.stringify({
        endpoints: ["POST /webhook", "GET /health", "GET /mappings"],
        error: "Not found",
    }));
}
// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------
function readBody(req) {
    return new Promise((resolve, reject) => {
        const chunks = [];
        req.on("data", (chunk) => chunks.push(chunk));
        req.on("end", () => resolve(Buffer.concat(chunks).toString()));
        req.on("error", reject);
    });
}
