"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 });
const express_1 = __importDefault(require("express"));
const auth_1 = require("../middleware/auth");
const config_1 = require("../config");
const enterpriseDb_1 = require("../services/enterpriseDb");
const enterpriseRepository_1 = require("../services/enterpriseRepository");
const analysisResultWindowStateStore_1 = require("../services/analysisResultWindowStateStore");
const resourceOwnership_1 = require("../services/resourceOwnership");
const rbac_1 = require("../services/rbac");
const VALID_SCENE_TYPES = new Set([
    'startup',
    'scrolling',
    'interaction',
    'memory',
    'cpu',
    'general',
]);
const router = express_1.default.Router();
function optionalString(value) {
    return typeof value === 'string' && value.trim().length > 0 ? value.trim() : undefined;
}
function optionalNumber(value) {
    if (value === undefined)
        return undefined;
    const parsed = Number(value);
    return Number.isFinite(parsed) ? parsed : undefined;
}
function parseMetadata(value) {
    if (!value || typeof value !== 'object' || Array.isArray(value))
        return undefined;
    const metadata = {};
    for (const [key, raw] of Object.entries(value)) {
        if (typeof raw === 'string' || typeof raw === 'number' || typeof raw === 'boolean' || raw === null) {
            metadata[key] = raw;
        }
    }
    return metadata;
}
router.get('/active', (req, res) => {
    const context = (0, auth_1.requireRequestContext)(req);
    if (!(0, rbac_1.hasRbacPermission)(context, 'analysis_result:read')) {
        (0, rbac_1.sendForbidden)(res, 'analysis_result:read permission is required');
        return;
    }
    const db = (0, enterpriseDb_1.openEnterpriseDb)();
    try {
        const repository = (0, analysisResultWindowStateStore_1.createAnalysisResultWindowStateRepository)(db);
        const scope = (0, enterpriseRepository_1.repositoryScopeFromRequestContext)(context);
        if ((0, config_1.resolveFeatureConfig)().enterprise && !repository.scopeGraphExists(scope)) {
            (0, resourceOwnership_1.sendResourceNotFound)(res, 'Workspace not found');
            return;
        }
        const activeWindows = repository.listActiveWindowStates(scope, {
            excludeWindowId: optionalString(req.query.excludeWindowId),
            limit: optionalNumber(req.query.limit),
        });
        res.json({
            success: true,
            activeWindows,
            count: activeWindows.length,
        });
    }
    catch (error) {
        console.error('[WorkspaceWindowRoutes] Failed to list active windows:', error);
        res.status(500).json({
            success: false,
            error: 'Failed to list active windows',
        });
    }
    finally {
        db.close();
    }
});
router.post('/:windowId/heartbeat', (req, res) => {
    const context = (0, auth_1.requireRequestContext)(req);
    if (!(0, rbac_1.hasRbacPermission)(context, 'analysis_result:read')) {
        (0, rbac_1.sendForbidden)(res, 'analysis_result:read permission is required');
        return;
    }
    const windowId = optionalString(req.params.windowId);
    if (!windowId) {
        res.status(400).json({
            success: false,
            error: 'windowId is required',
        });
        return;
    }
    const sceneType = optionalString(req.body?.sceneType);
    if (sceneType && !VALID_SCENE_TYPES.has(sceneType)) {
        res.status(400).json({
            success: false,
            error: 'Invalid sceneType',
        });
        return;
    }
    const db = (0, enterpriseDb_1.openEnterpriseDb)();
    try {
        const repository = (0, analysisResultWindowStateStore_1.createAnalysisResultWindowStateRepository)(db);
        const scope = (0, enterpriseRepository_1.repositoryScopeFromRequestContext)(context);
        const shouldEnsureScopeGraph = !(0, config_1.resolveFeatureConfig)().enterprise;
        if (!shouldEnsureScopeGraph && !repository.scopeGraphExists(scope)) {
            (0, resourceOwnership_1.sendResourceNotFound)(res, 'Workspace not found');
            return;
        }
        const windowState = repository.upsertWindowState(scope, {
            windowId,
            userId: context.userId,
            traceId: optionalString(req.body?.traceId),
            backendTraceId: optionalString(req.body?.backendTraceId),
            activeSessionId: optionalString(req.body?.activeSessionId),
            latestSnapshotId: optionalString(req.body?.latestSnapshotId),
            traceTitle: optionalString(req.body?.traceTitle),
            sceneType: sceneType,
            metadata: parseMetadata(req.body?.metadata),
            ttlMs: optionalNumber(req.body?.ttlMs),
        }, { ensureScopeGraph: shouldEnsureScopeGraph });
        const activeWindows = repository.listActiveWindowStates(scope, {
            excludeWindowId: windowId,
            limit: 20,
        });
        res.json({
            success: true,
            windowState,
            activeWindows,
        });
    }
    catch (error) {
        console.error('[WorkspaceWindowRoutes] Failed to persist heartbeat:', error);
        res.status(500).json({
            success: false,
            error: 'Failed to persist heartbeat',
        });
    }
    finally {
        db.close();
    }
});
exports.default = router;
//# sourceMappingURL=workspaceWindowRoutes.js.map