/**
 * Query Logger
 * Tracks database query execution with parameters, duration, and context
 */
// Private state (exposed on QueryLogger for targeted unit-test coverage)
const logs = new Map();
let currentContext = 'default';
const MAX_CONTEXTS = 1000;
const MAX_QUERIES_PER_CONTEXT = 500;
/**
 * QueryLogger tracks all database queries executed during a request context
 * Provides N+1 detection heuristic by flagging identical queries executed 5+ times
 * Sealed namespace for immutability
 */
export const QueryLogger = Object.freeze({
    // Exposed for rare-branch tests that deliberately corrupt the map.
    logs,
    getInstance() {
        return this;
    },
    /**
     * Set current request context ID
     */
    setContext(context) {
        currentContext = context;
        if (!logs.has(context)) {
            // Prevent unbounded growth of contexts
            if (logs.size >= MAX_CONTEXTS) {
                const firstKey = logs.keys().next().value;
                if (firstKey !== undefined) {
                    logs.delete(firstKey);
                }
            }
            logs.set(context, []);
        }
    },
    /**
     * Get current request context ID
     */
    getContext() {
        return currentContext;
    },
    /**
     * Log a query execution
     */
    logQuery(sql, params, duration, context = currentContext) {
        if (!logs.has(context)) {
            // Prevent unbounded growth of contexts
            if (logs.size >= MAX_CONTEXTS) {
                const firstKey = logs.keys().next().value;
                if (firstKey !== undefined) {
                    logs.delete(firstKey);
                }
            }
            logs.set(context, []);
        }
        const entry = {
            sql,
            params,
            duration,
            timestamp: new Date(),
            context,
        };
        const contextLogs = logs.get(context);
        if (Array.isArray(contextLogs)) {
            contextLogs.push(entry);
            // Prevent unbounded growth of queries per context
            if (contextLogs.length > MAX_QUERIES_PER_CONTEXT) {
                contextLogs.shift();
            }
        }
    },
    /**
     * Get query log for a context
     */
    getQueryLog(context = currentContext) {
        const contextLogs = logs.get(context);
        return Array.isArray(contextLogs) ? contextLogs : [];
    },
    /**
     * Get query summary (grouped by SQL) for a context
     */
    getQuerySummary(context = currentContext) {
        const queryLogs = this.getQueryLog(context);
        const summary = new Map();
        for (const log of queryLogs) {
            if (!summary.has(log.sql)) {
                summary.set(log.sql, { ...log, executionCount: 0 });
            }
            const entry = summary.get(log.sql);
            if (entry !== undefined) {
                entry.executionCount++;
            }
        }
        return summary;
    },
    /**
     * Get N+1 suspects (queries executed 5+ times in same context)
     * Simple heuristic: identical queries executed many times suggests N+1
     */
    getN1Suspects(context = currentContext, threshold = 5) {
        const summary = this.getQuerySummary(context);
        const suspects = [];
        for (const [, entry] of summary) {
            if (entry.executionCount >= threshold) {
                suspects.push(entry);
            }
        }
        return suspects;
    },
    /**
     * Clear logs for a context
     */
    clear(context) {
        if (context === undefined) {
            logs.clear();
            currentContext = 'default';
        }
        else {
            logs.delete(context);
        }
    },
    /**
     * Get all logs
     */
    getAllLogs() {
        const copy = new Map();
        for (const [key, value] of logs.entries()) {
            if (Array.isArray(value)) {
                copy.set(key, value);
            }
        }
        return copy;
    },
    /**
     * Get total query count for a context
     */
    getQueryCount(context = currentContext) {
        return this.getQueryLog(context).length;
    },
    /**
     * Get total duration for all queries in a context
     */
    getTotalDuration(context = currentContext) {
        const queryLogs = this.getQueryLog(context);
        return queryLogs.reduce((total, log) => total + log.duration, 0);
    },
});
