"use strict";
// SPDX-License-Identifier: AGPL-3.0-or-later
// Copyright (C) 2024-2026 Gracker (Chris)
// This file is part of SmartPerfetto. See LICENSE for details.
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.traceService = exports.uploadTrace = void 0;
exports.initializeUpload = initializeUpload;
exports.handleUpload = handleUpload;
exports.uploadChunk = uploadChunk;
exports.completeUpload = completeUpload;
exports.getTraceStatus = getTraceStatus;
exports.listTraces = listTraces;
exports.deleteTrace = deleteTrace;
exports.queryTrace = queryTrace;
exports.getTraceMetadata = getTraceMetadata;
const traceProcessorService_1 = require("../services/traceProcessorService");
const multer_1 = __importDefault(require("multer"));
const path_1 = __importDefault(require("path"));
const httpValue_1 = require("../utils/httpValue");
const traceUploadLimit_1 = require("../services/traceUploadLimit");
// Get the shared TraceProcessorService singleton
const traceService = (0, traceProcessorService_1.getTraceProcessorService)();
exports.traceService = traceService;
// memoryStorage buffers the entire upload in RAM — keep a hard 1 GiB ceiling here
// regardless of the shared upload limit, otherwise a 5 GiB upload would OOM Node.
// This legacy route is only mounted by dev scripts; the production path is simpleTraceRoutes.
const MEMORY_STORAGE_HARD_CAP_BYTES = 1024 * 1024 * 1024;
const storage = multer_1.default.memoryStorage();
const upload = (0, multer_1.default)({
    storage,
    limits: {
        fileSize: Math.min((0, traceUploadLimit_1.resolveTraceUploadLimitBytes)(), MEMORY_STORAGE_HARD_CAP_BYTES),
    },
});
// Listen for trace events
traceService.on('trace-status-changed', (trace) => {
    console.log(`Trace ${trace.id} status: ${trace.status}`);
});
// Initialize a trace upload
async function initializeUpload(req, res) {
    try {
        const { filename, size } = req.body;
        if (!filename || !size) {
            res.status(400).json({ error: 'Filename and size are required' });
            return;
        }
        const traceId = await traceService.initializeUpload(filename, parseInt(size));
        res.json({
            traceId,
            uploadUrl: `/api/traces/${traceId}/upload`,
        });
    }
    catch (error) {
        console.error('Failed to initialize upload:', error);
        res.status(500).json({ error: 'Failed to initialize upload' });
    }
}
// Upload a complete trace file
exports.uploadTrace = upload.single('trace');
async function handleUpload(req, res) {
    try {
        if (!req.file) {
            res.status(400).json({ error: 'No file uploaded' });
            return;
        }
        const { filename } = req.body;
        const traceId = await traceService.initializeUpload(filename || req.file.originalname, req.file.size);
        // Write the file
        const fs = require('fs');
        const tracePath = path_1.default.join(__dirname, '../../../uploads/traces', `${traceId}.trace`);
        fs.writeFileSync(tracePath, req.file.buffer);
        // Process the trace
        await traceService.completeUpload(traceId);
        const trace = traceService.getTrace(traceId);
        res.json({
            traceId,
            status: trace?.status,
            message: 'Trace uploaded successfully',
        });
    }
    catch (error) {
        console.error('Failed to upload trace:', error);
        res.status(500).json({ error: 'Failed to upload trace' });
    }
}
// Upload chunk for large files
async function uploadChunk(req, res) {
    try {
        const traceId = (0, httpValue_1.toSingleString)(req.params.traceId);
        const offsetHeader = (0, httpValue_1.toSingleString)(req.headers.offset);
        if (!traceId) {
            res.status(400).json({ error: 'traceId is required' });
            return;
        }
        if (!req.body || !Buffer.isBuffer(req.body)) {
            res.status(400).json({ error: 'Invalid chunk data' });
            return;
        }
        await traceService.uploadChunk(traceId, req.body, offsetHeader ? parseInt(offsetHeader, 10) : 0);
        res.json({ received: true });
    }
    catch (error) {
        console.error('Failed to upload chunk:', error);
        res.status(500).json({ error: 'Failed to upload chunk' });
    }
}
// Complete upload
async function completeUpload(req, res) {
    try {
        const traceId = (0, httpValue_1.toSingleString)(req.params.traceId);
        if (!traceId) {
            res.status(400).json({ error: 'traceId is required' });
            return;
        }
        await traceService.completeUpload(traceId);
        const trace = traceService.getTrace(traceId);
        res.json({
            traceId,
            status: trace?.status,
        });
    }
    catch (error) {
        console.error('Failed to complete upload:', error);
        res.status(500).json({ error: 'Failed to complete upload' });
    }
}
// Get trace status
async function getTraceStatus(req, res) {
    try {
        const traceId = (0, httpValue_1.toSingleString)(req.params.traceId);
        if (!traceId) {
            res.status(400).json({ error: 'traceId is required' });
            return;
        }
        const trace = traceService.getTrace(traceId);
        if (!trace) {
            res.status(404).json({ error: 'Trace not found' });
            return;
        }
        res.json(trace);
    }
    catch (error) {
        console.error('Failed to get trace status:', error);
        res.status(500).json({ error: 'Failed to get trace status' });
    }
}
// List all traces
async function listTraces(req, res) {
    try {
        const traces = traceService.getAllTraces();
        res.json({ traces });
    }
    catch (error) {
        console.error('Failed to list traces:', error);
        res.status(500).json({ error: 'Failed to list traces' });
    }
}
// Delete a trace
async function deleteTrace(req, res) {
    try {
        const traceId = (0, httpValue_1.toSingleString)(req.params.traceId);
        if (!traceId) {
            res.status(400).json({ error: 'traceId is required' });
            return;
        }
        await traceService.deleteTrace(traceId);
        res.json({ message: 'Trace deleted successfully' });
    }
    catch (error) {
        console.error('Failed to delete trace:', error);
        res.status(500).json({ error: 'Failed to delete trace' });
    }
}
// Query a trace
async function queryTrace(req, res) {
    try {
        const traceId = (0, httpValue_1.toSingleString)(req.params.traceId);
        const query = (0, httpValue_1.toSingleString)(req.query.q);
        if (!traceId) {
            res.status(400).json({ error: 'traceId is required' });
            return;
        }
        if (!query) {
            res.status(400).json({ error: 'Query parameter is required' });
            return;
        }
        const result = await traceService.query(traceId, query);
        res.json(result);
    }
    catch (error) {
        console.error('Failed to query trace:', error);
        res.status(500).json({ error: 'Failed to query trace' });
    }
}
// Get trace metadata
async function getTraceMetadata(req, res) {
    try {
        const traceId = (0, httpValue_1.toSingleString)(req.params.traceId);
        if (!traceId) {
            res.status(400).json({ error: 'traceId is required' });
            return;
        }
        const trace = traceService.getTrace(traceId);
        if (!trace) {
            res.status(404).json({ error: 'Trace not found' });
            return;
        }
        res.json({
            metadata: trace.metadata,
            status: trace.status,
            error: trace.error,
        });
    }
    catch (error) {
        console.error('Failed to get trace metadata:', error);
        res.status(500).json({ error: 'Failed to get trace metadata' });
    }
}
//# sourceMappingURL=traceProcessorController.js.map