"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.
Object.defineProperty(exports, "__esModule", { value: true });
exports.intervalHelpers = void 0;
exports.payloadToObjectRows = payloadToObjectRows;
exports.isLikelyAppProcessName = isLikelyAppProcessName;
exports.formatNsRangeLabel = formatNsRangeLabel;
exports.unwrapStepResult = unwrapStepResult;
/**
 * Convert columnar payload ({ columns, rows }) or array-of-objects to
 * a normalized array of row objects.
 *
 * Handles three formats:
 * 1. Already an array of objects → passthrough
 * 2. { columns: string[], rows: any[][] } → zip into objects
 * 3. Anything else → empty array
 */
function payloadToObjectRows(payload) {
    if (!payload)
        return [];
    // Already array of objects
    if (Array.isArray(payload) && payload.length > 0 && typeof payload[0] === 'object' && !Array.isArray(payload[0])) {
        return payload;
    }
    // Columnar format
    const columns = payload.columns;
    const rows = payload.rows;
    if (!Array.isArray(columns) || !Array.isArray(rows))
        return [];
    return rows.map((row) => {
        const obj = {};
        for (let i = 0; i < columns.length; i++) {
            obj[columns[i]] = row[i];
        }
        return obj;
    });
}
/**
 * Heuristic to determine if a process name is likely an app process
 * (as opposed to a system daemon like surfaceflinger or system_server).
 */
function isLikelyAppProcessName(name) {
    const n = (name || '').trim();
    if (!n)
        return false;
    if (n.startsWith('/'))
        return false; // e.g. /system/bin/surfaceflinger
    if (n.includes('surfaceflinger'))
        return false;
    if (n === 'system_server')
        return false;
    return true;
}
/**
 * Format a nanosecond time range as a human-readable label.
 * If referenceNs is provided, shows relative times (e.g., "2.03s–4.82s").
 * Otherwise computes duration (e.g., "持续 2.79s").
 *
 * Uses BigInt division for precision-safe conversion from ns to seconds.
 */
function formatNsRangeLabel(startTs, endTs, referenceNs) {
    try {
        const startBi = BigInt(String(startTs));
        const endBi = BigInt(String(endTs));
        const refBi = referenceNs !== undefined ? BigInt(String(referenceNs)) : startBi;
        // ns → ms (BigInt) → s (Number, safe range)
        const relStartS = Number((startBi - refBi) / 1000000n) / 1000;
        const relEndS = Number((endBi - refBi) / 1000000n) / 1000;
        return `${formatTimeValue(relStartS)}–${formatTimeValue(relEndS)}`;
    }
    catch {
        // Fallback: show duration
        const startN = Number(startTs);
        const endN = Number(endTs);
        const durS = (endN - startN) / 1e9;
        return `持续 ${formatTimeValue(durS)}`;
    }
}
/**
 * Format a time value in seconds to a human-readable format.
 * Examples: "2.034s", "1m23.456s", "0.123s"
 */
function formatTimeValue(seconds) {
    if (seconds < 0)
        return `-${formatTimeValue(-seconds)}`;
    if (seconds >= 60) {
        const m = Math.floor(seconds / 60);
        const s = seconds - m * 60;
        return `${m}m${s.toFixed(3)}s`;
    }
    return `${seconds.toFixed(3)}s`;
}
/**
 * Unwrap a value that may be a raw payload OR a SkillExecutor StepResult
 * wrapper ({ data, success, stepId, ... }).  Returns the inner payload so
 * that payloadToObjectRows always receives an array or columnar object.
 *
 * rawResults (context.results) maps step IDs to StepResult objects.
 * Strategies must unwrap before calling payloadToObjectRows.
 */
function unwrapStepResult(value) {
    if (!value || typeof value !== 'object')
        return value;
    const maybe = value;
    const isStepResult = typeof maybe.stepId === 'string' &&
        typeof maybe.success === 'boolean' &&
        Object.prototype.hasOwnProperty.call(maybe, 'data');
    if (isStepResult) {
        return unwrapStepResult(maybe.data);
    }
    const rawResults = maybe.rawResults;
    if (rawResults && typeof rawResults === 'object') {
        if (Object.prototype.hasOwnProperty.call(maybe, 'data')) {
            return unwrapStepResult(maybe.data);
        }
        const rootData = rawResults.root?.data;
        if (rootData !== undefined) {
            return unwrapStepResult(rootData);
        }
        for (const step of Object.values(rawResults)) {
            if (step && typeof step === 'object' && Object.prototype.hasOwnProperty.call(step, 'data')) {
                return unwrapStepResult(step.data);
            }
        }
    }
    return value;
}
/**
 * Pre-built helpers instance for use in strategy extractIntervals implementations.
 */
exports.intervalHelpers = {
    payloadToObjectRows,
    isLikelyAppProcessName,
    formatNsRangeLabel,
};
//# sourceMappingURL=helpers.js.map