"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.startOpenAICompatProxyServer = void 0;
const http = __importStar(require("http"));
const crypto_1 = require("crypto");
const undici_1 = require("undici");
const proxy_daemon_paths_1 = require("../proxy-daemon-paths");
const logging_1 = require("../../services/logging");
const messages_route_1 = require("./messages-route");
const http_helpers_1 = require("./http-helpers");
const REQUEST_ID_HEADER = 'x-ccs-request-id';
// Loose UUID-ish guard: accepts UUIDs and similar opaque ids; rejects empty / control chars.
const REQUEST_ID_PATTERN = /^[A-Za-z0-9._-]{8,128}$/;
function resolveInboundRequestId(headers) {
    const raw = headers[REQUEST_ID_HEADER];
    if (typeof raw === 'string' && REQUEST_ID_PATTERN.test(raw.trim())) {
        return raw.trim();
    }
    return (0, crypto_1.randomUUID)();
}
function startOpenAICompatProxyServer(options) {
    const host = options.host?.trim() || '127.0.0.1';
    const logger = (0, logging_1.createLogger)('proxy:openai-compat', {
        profileName: options.profile.profileName,
        host,
        port: options.port,
    });
    const insecureDispatcher = options.insecure
        ? new undici_1.Agent({ connect: { rejectUnauthorized: false } })
        : undefined;
    const server = http.createServer((req, res) => {
        const requestId = resolveInboundRequestId(req.headers);
        res.setHeader(REQUEST_ID_HEADER, requestId);
        void (0, logging_1.withRequestContext)({ requestId }, async () => {
            const method = req.method || 'GET';
            const requestUrl = req.url || '/';
            const parsedUrl = new URL(requestUrl, 'http://127.0.0.1');
            const pathname = parsedUrl.pathname.length > 1 ? parsedUrl.pathname.replace(/\/+$/, '') : parsedUrl.pathname;
            await handleProxyRequest(req, res, method, pathname);
        });
    });
    async function handleProxyRequest(req, res, method, pathname) {
        if ((method === 'GET' || method === 'HEAD') && pathname === '/health') {
            if (method === 'HEAD') {
                res.writeHead(200, { 'Content-Type': 'application/json' });
                res.end();
            }
            else {
                (0, http_helpers_1.writeJson)(res, 200, {
                    ok: true,
                    service: proxy_daemon_paths_1.OPENAI_COMPAT_PROXY_SERVICE_NAME,
                    host,
                    profile: options.profile.profileName,
                    port: options.port,
                });
            }
            return;
        }
        if ((method === 'GET' || method === 'HEAD') && pathname === '/') {
            if (method === 'HEAD') {
                res.writeHead(200, { 'Content-Type': 'application/json' });
                res.end();
            }
            else {
                (0, http_helpers_1.writeJson)(res, 200, {
                    ok: true,
                    service: proxy_daemon_paths_1.OPENAI_COMPAT_PROXY_SERVICE_NAME,
                    bind: {
                        host,
                        port: options.port,
                    },
                    profile: {
                        name: options.profile.profileName,
                        provider: options.profile.provider,
                        model: options.profile.model || null,
                    },
                    endpoints: ['/health', '/v1/messages', '/v1/models'],
                });
            }
            return;
        }
        if (method === 'GET' && pathname === '/v1/models') {
            if (!(0, messages_route_1.validateIncomingProxyAuth)(req.headers, options.authToken)) {
                (0, http_helpers_1.writeJson)(res, 401, {
                    type: 'error',
                    error: {
                        type: 'authentication_error',
                        message: 'Missing or invalid local proxy token',
                    },
                });
                return;
            }
            (0, messages_route_1.handleProxyModelsRequest)(res, options.profile);
            return;
        }
        if (method === 'POST' && pathname === '/v1/messages') {
            await (0, messages_route_1.handleProxyMessagesRequest)(req, res, options.profile, options.authToken, insecureDispatcher);
            return;
        }
        logger.warn('http.not_found', 'Rejected unknown proxy route', {
            method,
            pathname,
        });
        (0, http_helpers_1.writeJson)(res, 404, { error: 'Not found' });
    }
    logger.info('server.start', 'OpenAI-compatible proxy server listening', {
        baseUrl: `http://${host}:${options.port}`,
    });
    server.on('close', () => {
        logger.info('server.stop', 'OpenAI-compatible proxy server stopped');
        void insecureDispatcher?.close();
    });
    server.listen(options.port, host);
    return server;
}
exports.startOpenAICompatProxyServer = startOpenAICompatProxyServer;
//# sourceMappingURL=proxy-server.js.map