"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.SymbolResolver = void 0;
const breakpadSymParser_1 = require("./breakpadSymParser");
const kallsymsParser_1 = require("./kallsymsParser");
const r8MappingParser_1 = require("./r8MappingParser");
function toCandidate(chunk, confidence) {
    return {
        chunkId: chunk.chunkId,
        ...(chunk.codebaseId ? { codebaseId: chunk.codebaseId } : {}),
        ...(chunk.filePath ? { filePath: chunk.filePath } : {}),
        ...(chunk.lineRange ? { lineRange: chunk.lineRange } : {}),
        ...(chunk.symbol ? { symbol: chunk.symbol } : {}),
        ...(chunk.language ? { language: chunk.language } : {}),
        confidence,
    };
}
class SymbolResolver {
    constructor(store) {
        this.store = store;
    }
    resolveApp(opts) {
        const retraced = opts.r8MappingText
            ? (0, r8MappingParser_1.retraceR8Symbol)((0, r8MappingParser_1.parseR8Mapping)(opts.r8MappingText), {
                obfuscatedSymbol: opts.symbol,
                obfuscatedClass: opts.obfuscatedClass,
                obfuscatedMethod: opts.obfuscatedMethod,
                line: opts.line,
            })
            : undefined;
        const querySymbol = retraced?.originalSymbol ?? opts.symbol;
        const symbolName = retraced?.originalName ?? querySymbol.split('.').pop() ?? querySymbol;
        const topK = opts.topK ?? 5;
        const base = {
            kinds: ['app_source'],
            topK,
            ...(opts.codebaseId ? { codebaseIds: [opts.codebaseId] } : {}),
            ...(opts.buildId ? { buildId: opts.buildId } : {}),
        };
        const exact = this.store.search(querySymbol, {
            ...base,
            symbolExact: symbolName,
        });
        if (exact.results.length > 0) {
            return {
                success: true,
                query: querySymbol,
                candidates: exact.results
                    .filter(hit => hit.chunk)
                    .map(hit => toCandidate(hit.chunk, 'exact')),
                degradedReason: opts.buildId ? undefined : 'symbol_only_low_confidence',
            };
        }
        if (opts.filePath) {
            const byFile = this.store.search(querySymbol, {
                ...base,
                filePathExact: opts.filePath,
            });
            if (byFile.results.length > 0) {
                return {
                    success: true,
                    query: querySymbol,
                    candidates: byFile.results
                        .filter(hit => hit.chunk)
                        .map(hit => toCandidate(hit.chunk, 'file')),
                    degradedReason: opts.buildId ? undefined : 'symbol_only_low_confidence',
                };
            }
        }
        const text = this.store.search(querySymbol, base);
        return {
            success: text.results.length > 0,
            query: querySymbol,
            candidates: text.results
                .filter(hit => hit.chunk)
                .map(hit => toCandidate(hit.chunk, 'text')),
            degradedReason: text.results.length > 0
                ? (opts.buildId ? undefined : 'symbol_only_low_confidence')
                : 'no_match',
        };
    }
    resolveKernel(opts) {
        let query = opts.symbol;
        if (!query && opts.address && (opts.kallsymsText || opts.systemMapText)) {
            const parsed = (0, kallsymsParser_1.parseKallsyms)(opts.kallsymsText ?? opts.systemMapText ?? '');
            const resolved = (0, kallsymsParser_1.resolveKallsymsAddress)(parsed, parseAddress(opts.address));
            query = resolved?.entry.symbol;
        }
        if (!query) {
            return { success: false, query: opts.address ?? '', candidates: [], degradedReason: 'no_match' };
        }
        return this.resolveSourceKind(query, 'kernel_source', {
            codebaseId: opts.codebaseId,
            vendor: opts.vendor,
            buildId: opts.buildId,
            topK: opts.topK,
        });
    }
    resolveNative(opts) {
        let query = opts.symbol;
        if (!query && opts.address && opts.breakpadSymText) {
            const module = (0, breakpadSymParser_1.parseBreakpadSym)(opts.breakpadSymText);
            const resolved = (0, breakpadSymParser_1.resolveBreakpadAddress)(module, parseAddress(opts.address));
            query = resolved?.func.name;
        }
        if (!query) {
            return { success: false, query: opts.address ?? '', candidates: [], degradedReason: 'no_match' };
        }
        return this.resolveSourceKind(query, 'aosp', {
            codebaseId: opts.codebaseId,
            buildId: opts.buildId,
            topK: opts.topK,
        });
    }
    resolveSourceKind(symbol, kind, opts) {
        const topK = opts.topK ?? 5;
        const symbolName = symbol.split('::').pop()?.split('.').pop() ?? symbol;
        const base = {
            kinds: [kind],
            topK,
            ...(opts.codebaseId ? { codebaseIds: [opts.codebaseId] } : {}),
            ...(opts.vendor ? { vendor: opts.vendor } : {}),
            ...(opts.buildId ? { buildId: opts.buildId } : {}),
        };
        const exact = this.store.search(symbol, { ...base, symbolExact: symbolName });
        const result = exact.results.length > 0 ? exact : this.store.search(symbol, base);
        return {
            success: result.results.length > 0,
            query: symbol,
            candidates: result.results
                .filter(hit => hit.chunk)
                .map(hit => toCandidate(hit.chunk, exact.results.length > 0 ? 'exact' : 'text')),
            degradedReason: result.results.length > 0
                ? (opts.buildId ? undefined : 'symbol_only_low_confidence')
                : 'no_match',
        };
    }
}
exports.SymbolResolver = SymbolResolver;
function parseAddress(value) {
    const trimmed = value.trim();
    return BigInt(trimmed.startsWith('0x') || trimmed.startsWith('0X') ? trimmed : `0x${trimmed}`);
}
//# sourceMappingURL=symbolResolver.js.map