"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const express_1 = __importDefault(require("express"));
const zlib_1 = require("zlib");
const util_1 = require("util");
const processor_1 = require("../otel/processor");
const Trace_1 = require("../dao/Trace");
const socket_1 = require("../trpc/socket");
const gunzipAsync = (0, util_1.promisify)(zlib_1.gunzip);
const inflateAsync = (0, util_1.promisify)(zlib_1.inflate);
const otelRouter = express_1.default.Router();
const trace_1 = require("./opentelemetry/proto/trace/v1/trace");
// Request: POST /v1/traces
otelRouter.post('/traces', (req, res) => __awaiter(void 0, void 0, void 0, function* () {
    try {
        console.debug(`[OTEL] Received OpenTelemetry traces request: ${req.method} ${req.path}`);
        console.debug(`[OTEL] Content-Type: ${req.get('content-type')}`);
        console.debug(`[OTEL] Content-Encoding: ${req.get('content-encoding')}`);
        console.debug(`[OTEL] Content-Length: ${req.get('content-length')}`);
        const contentType = req.get('content-type') || '';
        const contentEncoding = req.get('content-encoding');
        // Check content-type
        if (!contentType ||
            (!contentType.includes('application/x-protobuf') &&
                !contentType.includes('application/json'))) {
            return res.status(415).json({
                error: 'Unsupported Media Type',
                message: 'Content-Type must be application/x-protobuf or application/json',
            });
        }
        // Check content-encoding
        if (contentEncoding && !['gzip', 'deflate'].includes(contentEncoding)) {
            return res.status(415).json({
                error: 'Unsupported Content Encoding',
                message: `Unsupported content encoding: ${contentEncoding}`,
            });
        }
        let body = req.body;
        if (!body || body.length === 0) {
            console.error('[OTEL] Empty request body');
            return res.status(400).json({
                error: 'Bad Request',
                message: 'Empty request body',
            });
        }
        // Handle compressed data
        try {
            if (contentEncoding === 'gzip') {
                body = yield gunzipAsync(body);
            }
            else if (contentEncoding === 'deflate') {
                body = yield inflateAsync(body);
            }
        }
        catch (error) {
            console.error('[OTEL] Failed to decompress request body:', error);
            return res.status(400).json({
                error: 'Bad Request',
                message: 'Failed to decompress request body',
            });
        }
        let resourceSpans;
        // Parse the body based on content type
        if (contentType.includes('application/x-protobuf')) {
            try {
                const traceData = trace_1.opentelemetry.proto.trace.v1.TracesData.deserializeBinary(body).toObject();
                resourceSpans = traceData.resource_spans;
            }
            catch (error) {
                console.error('[OTEL] Failed to parse protobuf:', error);
                return res.status(422).json({
                    error: 'Unprocessable Entity',
                    message: 'Failed to parse OpenTelemetry protobuf data',
                });
            }
        }
        else if (contentType.includes('application/json')) {
            try {
                const jsonData = JSON.parse(body.toString());
                resourceSpans = jsonData.resourceSpans;
            }
            catch (error) {
                console.error('[OTEL] Failed to parse JSON:', error);
                return res.status(422).json({
                    error: 'Unprocessable Entity',
                    message: 'Failed to parse JSON data',
                });
            }
        }
        if (!resourceSpans || !Array.isArray(resourceSpans)) {
            return res.status(422).json({
                error: 'Invalid or missing resourceSpans data',
                message: 'Invalid OpenTelemetry data',
            });
        }
        const spans = processor_1.SpanProcessor.batchProcessOTLPTraces(resourceSpans);
        // Save spans to the databases
        yield Trace_1.SpanDao.saveSpans(spans);
        // Broadcast spans to the run room
        socket_1.SocketManager.broadcastSpanDataToRunRoom(spans);
        return res.status(200).json({
            message: `Processed traces successfully`,
        });
    }
    catch (error) {
        console.error('Error processing OpenTelemetry traces:', error);
        res.status(500).json({
            error: 'Internal Server Error',
            message: 'Failed to process traces',
        });
    }
}));
exports.default = otelRouter;
