"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 __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 () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.runCaptureAndroidCommand = runCaptureAndroidCommand;
exports.runCapturePresetsCommand = runCapturePresetsCommand;
exports.runCaptureConfigCommand = runCaptureConfigCommand;
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const bootstrap_1 = require("../bootstrap");
const renderer_1 = require("../repl/renderer");
const stdio_1 = require("../io/stdio");
const runtimeGuard_1 = require("../services/runtimeGuard");
const cliAnalyzeService_1 = require("../services/cliAnalyzeService");
const turnRunner_1 = require("../services/turnRunner");
const captureConfig_1 = require("../services/captureConfig");
const androidCapture_1 = require("../services/androidCapture");
const constants_1 = require("../constants");
async function runCaptureAndroidCommand(args) {
    const { paths } = (0, bootstrap_1.bootstrap)({ envFile: args.envFile, sessionDir: args.sessionDir, requireLlm: false });
    const format = args.format ?? 'text';
    const outPath = path.resolve(args.out);
    let service;
    try {
        const configInput = resolveAndroidConfigInput(args);
        if (format === 'text') {
            const preset = configInput.preset ? ` preset=${configInput.preset}` : '';
            const source = configInput.configPath ? ` config=${configInput.configPath}` : preset;
            console.log(`capturing Android trace${source} -> ${outPath}`);
        }
        else if (format === 'ndjson') {
            console.log(JSON.stringify({
                type: 'capture_start',
                target: 'android',
                preset: configInput.preset,
                configPath: configInput.configPath,
                out: outPath,
            }));
        }
        const capture = await (0, androidCapture_1.captureAndroidTrace)({
            configText: configInput.configText,
            configPath: configInput.configPath,
            configDurationMs: configInput.configDurationMs,
            app: args.app,
            preset: configInput.preset,
            durationSeconds: configInput.durationSeconds,
            out: outPath,
            serial: args.serial,
            sideload: args.sideload,
            traceboxPath: args.tracebox,
            noGuardrails: args.noGuardrails,
            adbPath: args.adb,
            killStale: args.killStale,
            backendRoot: process.cwd(),
            runner: args.runner,
        });
        if (!args.analyze) {
            printCaptureResult(format, capture);
            return 0;
        }
        printPreflightWarnings(format, capture);
        const renderer = (0, renderer_1.createRenderer)({ verbose: args.verbose, useColor: !args.noColor, format });
        service = new cliAnalyzeService_1.CliAnalyzeService();
        const query = args.query?.trim() || constants_1.DEFAULT_ANALYSIS_QUERY;
        let exitCode = 0;
        await (0, stdio_1.withConsoleLogToStderr)(renderer.format !== 'text', async () => {
            (0, runtimeGuard_1.assertAnalysisRuntimeReady)();
            const turn = await (0, turnRunner_1.startSession)({ paths, service: service, renderer }, {
                tracePath: capture.out,
                query,
                analysisMode: args.analysisMode,
                capture,
            });
            capture.analysis = {
                sessionId: turn.sessionId,
                sessionDir: turn.sessionDir,
                turn: turn.turn,
                success: turn.success,
            };
            exitCode = turn.success ? 0 : 1;
        });
        return exitCode;
    }
    catch (err) {
        printError(format, err.message);
        return 1;
    }
    finally {
        await service?.shutdown();
    }
}
async function runCapturePresetsCommand(args) {
    (0, bootstrap_1.bootstrap)({ envFile: args.envFile, sessionDir: args.sessionDir, requireLlm: false });
    const format = args.format ?? 'text';
    const presets = (0, captureConfig_1.listCapturePresets)();
    if (format === 'json' || format === 'ndjson') {
        console.log(JSON.stringify({ ok: true, presets }, null, format === 'json' ? 2 : 0));
        return 0;
    }
    console.log('SmartPerfetto capture presets');
    for (const preset of presets) {
        console.log(`${preset.id.padEnd(10)} ${preset.label} (${preset.defaultDurationSeconds}s)`);
        console.log(`  ${preset.description}`);
    }
    return 0;
}
async function runCaptureConfigCommand(args) {
    (0, bootstrap_1.bootstrap)({ envFile: args.envFile, sessionDir: args.sessionDir, requireLlm: false });
    const format = args.format ?? 'text';
    try {
        const preset = (0, captureConfig_1.getCapturePreset)(args.preset);
        const durationSeconds = args.durationSeconds ?? preset.defaultDurationSeconds;
        const configText = (0, captureConfig_1.renderAndroidTraceConfig)({
            target: 'android',
            preset: args.preset,
            app: args.app,
            durationSeconds,
            cuj: args.cuj,
            extraAtraceCategories: args.categories,
        });
        if (args.out) {
            const outPath = path.resolve(args.out);
            fs.mkdirSync(path.dirname(outPath), { recursive: true });
            fs.writeFileSync(outPath, configText, 'utf-8');
            if (format === 'json' || format === 'ndjson') {
                console.log(JSON.stringify({ ok: true, preset: args.preset, out: outPath }, null, format === 'json' ? 2 : 0));
            }
            else {
                console.log(outPath);
            }
        }
        else {
            if (format === 'json' || format === 'ndjson') {
                console.log(JSON.stringify({ ok: true, preset: args.preset, config: configText }, null, format === 'json' ? 2 : 0));
            }
            else {
                process.stdout.write(configText);
            }
        }
        return 0;
    }
    catch (err) {
        printError(format, err.message);
        return 1;
    }
}
function resolveAndroidConfigInput(args) {
    if (args.config) {
        const config = (0, captureConfig_1.readTraceConfigFile)(args.config, { durationSeconds: args.durationSeconds });
        const configText = (0, captureConfig_1.addAtraceCategories)(config.textproto, args.categories ?? []);
        return {
            configText,
            configPath: config.path,
            configDurationMs: extractDurationFromText(configText, config.durationMs),
            durationSeconds: args.durationSeconds,
        };
    }
    if (!args.app?.trim()) {
        throw new Error('--app <package|*> is required when --config is not provided');
    }
    const preset = args.preset ?? 'overview';
    if (!(0, captureConfig_1.isCapturePresetId)(preset)) {
        throw new Error(`invalid --preset ${preset}`);
    }
    const definition = (0, captureConfig_1.getCapturePreset)(preset);
    const durationSeconds = args.durationSeconds ?? definition.defaultDurationSeconds;
    return {
        configText: (0, captureConfig_1.renderAndroidTraceConfig)({
            target: 'android',
            preset,
            app: args.app,
            durationSeconds,
            extraAtraceCategories: args.categories,
            cuj: args.cuj,
        }),
        preset,
        durationSeconds,
    };
}
function printCaptureResult(format, capture) {
    printPreflightWarnings(format, capture);
    if (format === 'json' || format === 'ndjson') {
        console.log(JSON.stringify({ ok: true, type: 'capture_complete', capture }, null, format === 'json' ? 2 : 0));
        return;
    }
    console.log(capture.out);
}
function printPreflightWarnings(format, capture) {
    if (format !== 'text')
        return;
    for (const warning of capture.preflight?.warnings ?? []) {
        console.error(`Warning: ${warning}`);
    }
}
function extractDurationFromText(textproto, fallback) {
    const match = [...textproto.matchAll(/^\s*duration_ms\s*:\s*(\d+)\s*$/gm)];
    const last = match[match.length - 1]?.[1];
    if (!last)
        return fallback;
    const value = Number.parseInt(last, 10);
    return Number.isFinite(value) && value > 0 ? value : fallback;
}
function printError(format, message) {
    if (format === 'json' || format === 'ndjson') {
        console.error(JSON.stringify({ ok: false, type: 'error', error: message }));
        return;
    }
    console.error(`Error: ${message}`);
}
//# sourceMappingURL=capture.js.map