// engine/webhook-server.ts — Incoming HTTP webhook server for Planu (SPEC-359)
import { createServer } from 'node:http';
/** Simple HTTP router for webhook endpoints */
export class WebhookRouter {
    routes = [];
    add(method, path, handler) {
        const pattern = path instanceof RegExp ? path : new RegExp(`^${path}$`);
        this.routes.push({ method: method.toUpperCase(), pathPattern: pattern, handler });
    }
    async handle(req, res) {
        const url = req.url ?? '/';
        const method = req.method ?? 'GET';
        const path = url.split('?')[0] ?? url;
        let body = '';
        await new Promise((resolve) => {
            req.on('data', (chunk) => {
                body += chunk.toString();
            });
            req.on('end', resolve);
        });
        const route = this.routes.find((r) => r.method === method && r.pathPattern.test(path));
        if (route === undefined) {
            res.writeHead(404, { 'Content-Type': 'application/json' });
            res.end(JSON.stringify({ error: 'Not Found' }));
            return;
        }
        try {
            await route.handler(req, res, body);
        }
        catch (err) {
            const message = err instanceof Error ? err.message : String(err);
            res.writeHead(500, { 'Content-Type': 'application/json' });
            res.end(JSON.stringify({ error: message }));
        }
    }
}
/** Verify Bearer token from Authorization header */
export function verifyBearerToken(req, secret) {
    const auth = req.headers.authorization;
    if (auth === undefined || auth === '') {
        return false;
    }
    const [scheme, token] = auth.split(' ');
    return scheme === 'Bearer' && token === secret;
}
/** Singleton server instance */
let activeServer = null;
export function getActiveServer() {
    return activeServer;
}
export function setActiveServer(server) {
    activeServer = server;
}
/** Start the HTTP server on the given port with the provided router */
export async function startWebhookServer(port, router) {
    return new Promise((resolve, reject) => {
        const server = createServer((req, res) => {
            router.handle(req, res).catch((err) => {
                const message = err instanceof Error ? err.message : String(err);
                res.writeHead(500, { 'Content-Type': 'application/json' });
                res.end(JSON.stringify({ error: message }));
            });
        });
        server.on('error', reject);
        server.listen(port, () => {
            setActiveServer(server);
            resolve(server);
        });
    });
}
/** Stop the active server */
export async function stopWebhookServer() {
    const server = getActiveServer();
    if (server === null) {
        return;
    }
    await new Promise((resolve, reject) => {
        server.close((err) => {
            if (err !== undefined) {
                reject(err);
                return;
            }
            resolve();
        });
    });
    setActiveServer(null);
}
/** Generate OpenAPI 3.0 YAML documentation for the webhook server */
export function generateWebhookOpenApiYaml(port) {
    return [
        'openapi: "3.0.3"',
        'info:',
        '  title: Planu Incoming Webhook API',
        '  version: "1.0.0"',
        '  description: REST API for creating and managing Planu specs via HTTP',
        `servers:`,
        `  - url: http://localhost:${port}`,
        `    description: Local Planu webhook server`,
        'components:',
        '  securitySchemes:',
        '    bearerAuth:',
        '      type: http',
        '      scheme: bearer',
        'security:',
        '  - bearerAuth: []',
        'paths:',
        '  /api/specs:',
        '    get:',
        '      summary: List all specs',
        '      operationId: listSpecs',
        '      responses:',
        '        "200":',
        '          description: Array of spec objects',
        '        "401":',
        '          description: Unauthorized',
        '    post:',
        '      summary: Create a new spec',
        '      operationId: createSpec',
        '      requestBody:',
        '        required: true',
        '        content:',
        '          application/json:',
        '            schema:',
        '              type: object',
        '              required: [projectPath, title]',
        '              properties:',
        '                projectPath:',
        '                  type: string',
        '                title:',
        '                  type: string',
        '                description:',
        '                  type: string',
        '      responses:',
        '        "201":',
        '          description: Spec created',
        '        "400":',
        '          description: Bad request',
        '        "401":',
        '          description: Unauthorized',
        '  /api/specs/{id}:',
        '    patch:',
        '      summary: Update spec status',
        '      operationId: updateSpecStatus',
        '      parameters:',
        '        - name: id',
        '          in: path',
        '          required: true',
        '          schema:',
        '            type: string',
        '      requestBody:',
        '        required: true',
        '        content:',
        '          application/json:',
        '            schema:',
        '              type: object',
        '              required: [projectPath, status]',
        '              properties:',
        '                projectPath:',
        '                  type: string',
        '                status:',
        '                  type: string',
        '      responses:',
        '        "200":',
        '          description: Status updated',
        '        "401":',
        '          description: Unauthorized',
    ].join('\n');
}
//# sourceMappingURL=webhook-server.js.map