"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.isDebugSimple = isDebugSimple;
exports.isDebug = isDebugSimple;
exports.debugLogSimple = debugLogSimple;
exports.debugLog = debugLogSimple;
exports.debugDirSimple = debugDirSimple;
exports.debugDir = debugDirSimple;
exports.debugFnSimple = debugFnSimple;
exports.debugFn = debugFnSimple;
exports.debuglog = debuglog;
exports.debugtime = debugtime;
exports.debugDirNs = debugDirNs;
exports.debugFnNs = debugFnNs;
exports.debugLogNs = debugLogNs;
exports.isDebugNs = isDebugNs;
/**
 * @fileoverview Debug logging utilities with lazy loading and environment-based control.
 * Provides Socket CLI specific debug functionality and logging formatters.
 */
const ENV_1 = require("./constants/ENV");
const objects_1 = require("./objects");
const strings_1 = require("./strings");
// IMPORTANT: Do not use destructuring here - use direct assignment instead.
// tsgo has a bug that incorrectly transpiles destructured exports, resulting in
// `exports.SomeName = void 0;` which causes runtime errors.
// See: https://github.com/SocketDev/socket-packageurl-js/issues/3
const ReflectApply = Reflect.apply;
let _debugJs;
/**
 * Lazily load the debug module.
 * @private
 */
/*@__NO_SIDE_EFFECTS__*/
function getDebugJs() {
    if (_debugJs === undefined) {
        // The 'debug' package is browser safe.
        const debugExport = /*@__PURE__*/ require('../external/debug');
        _debugJs = debugExport.default;
    }
    return _debugJs;
}
const debugByNamespace = new Map();
/**
 * Get or create a debug instance for a namespace.
 * @private
 */
/*@__NO_SIDE_EFFECTS__*/
function getDebugJsInstance(namespace) {
    let inst = debugByNamespace.get(namespace);
    if (inst) {
        return inst;
    }
    const debugJs = getDebugJs();
    if (!ENV_1.DEBUG &&
        ENV_1.SOCKET_CLI_DEBUG &&
        (namespace === 'error' || namespace === 'notice')) {
        debugJs.enable(namespace);
    }
    inst = debugJs(namespace);
    inst.log = customLog;
    debugByNamespace.set(namespace, inst);
    return inst;
}
let _util;
/**
 * Lazily load the util module.
 * @private
 */
/*@__NO_SIDE_EFFECTS__*/
function getUtil() {
    if (_util === undefined) {
        // Use non-'node:' prefixed require to avoid Webpack errors.
        // eslint-disable-next-line n/prefer-node-protocol
        _util = /*@__PURE__*/ require('util');
    }
    return _util;
}
/**
 * Custom log function for debug output.
 * @private
 */
/*@__NO_SIDE_EFFECTS__*/
function customLog() {
    const { logger } = /*@__PURE__*/ require('./logger.js');
    const debugJs = getDebugJs();
    const util = getUtil();
    const inspectOpts = debugJs.inspectOpts
        ? {
            ...debugJs.inspectOpts,
            showHidden: debugJs.inspectOpts.showHidden === null
                ? undefined
                : debugJs.inspectOpts.showHidden,
        }
        : {};
    ReflectApply(logger.info, logger, [
        util.formatWithOptions(inspectOpts, ...arguments),
    ]);
}
/**
 * Extract options from namespaces parameter.
 * @private
 */
/*@__NO_SIDE_EFFECTS__*/
function extractOptions(namespaces) {
    return namespaces !== null && typeof namespaces === 'object'
        ? { __proto__: null, ...namespaces }
        : { __proto__: null, namespaces };
}
/**
 * Check if debug is enabled for given namespaces.
 * @private
 */
/*@__NO_SIDE_EFFECTS__*/
function isEnabled(namespaces) {
    if (typeof namespaces !== 'string' || !namespaces || namespaces === '*') {
        return true;
    }
    // Namespace splitting logic is based the 'debug' package implementation:
    // https://github.com/debug-js/debug/blob/4.4.1/src/common.js#L169-L173.
    const split = namespaces
        .trim()
        .replace(/\s+/g, ',')
        .split(',')
        .filter(Boolean);
    const names = [];
    const skips = [];
    for (const ns of split) {
        if (ns.startsWith('-')) {
            skips.push(ns.slice(1));
        }
        else {
            names.push(ns);
        }
    }
    if (names.length && !names.some(ns => getDebugJsInstance(ns).enabled)) {
        return false;
    }
    return skips.every(ns => !getDebugJsInstance(ns).enabled);
}
/**
 * Debug output for object inspection.
 */
/*@__NO_SIDE_EFFECTS__*/
/* c8 ignore start - Debug utilities only used in development. */
function debugDirNs(namespacesOrOpts, obj, inspectOpts) {
    const options = extractOptions(namespacesOrOpts);
    const { namespaces } = options;
    if (!isEnabled(namespaces)) {
        return;
    }
    if (inspectOpts === undefined) {
        const debugJs = getDebugJs();
        inspectOpts = debugJs.inspectOpts;
    }
    const { spinner = /*@__PURE__*/ require('./constants/spinner.js').default } = options;
    const wasSpinning = spinner.isSpinning;
    spinner.stop();
    const { logger } = /*@__PURE__*/ require('./logger.js');
    logger.dir(obj, inspectOpts);
    if (wasSpinning) {
        spinner.start();
    }
}
/* c8 ignore stop */
let pointingTriangle;
/**
 * Debug output with function name prefix.
 */
/*@__NO_SIDE_EFFECTS__*/
/* c8 ignore start - Debug utilities only used in development. */
function debugFnNs(namespacesOrOpts, ...args) {
    const options = extractOptions(namespacesOrOpts);
    const { namespaces } = options;
    if (!isEnabled(namespaces)) {
        return;
    }
    const { stack } = new Error();
    let lineCount = 0;
    let lineStart = 0;
    let name = 'anonymous';
    // Scan the stack trace character-by-character to find the 4th line
    // (index 3), which is typically the caller of debugFn.
    if (stack) {
        for (let i = 0, { length } = stack; i < length; i += 1) {
            if (stack.charCodeAt(i) === 10 /*'\n'*/) {
                lineCount += 1;
                if (lineCount < 4) {
                    // Store the start index of the next line.
                    lineStart = i + 1;
                }
                else {
                    // Extract the full line and trim it.
                    const line = stack.slice(lineStart, i).trimStart();
                    // Match the function name portion (e.g., "async runFix").
                    const match = /(?<=^at\s+).*?(?=\s+\(|$)/.exec(line)?.[0];
                    if (match) {
                        name = match
                            // Strip known V8 invocation prefixes to get the name.
                            .replace(/^(?:async|bound|get|new|set)\s+/, '');
                        if (name.startsWith('Object.')) {
                            // Strip leading 'Object.' if not an own property of Object.
                            const afterDot = name.slice(7 /*'Object.'.length*/);
                            if (!(0, objects_1.hasOwn)(Object, afterDot)) {
                                name = afterDot;
                            }
                        }
                    }
                    break;
                }
            }
        }
    }
    if (pointingTriangle === undefined) {
        const supported = 
        /*@__PURE__*/ require('../external/@socketregistry/is-unicode-supported')();
        pointingTriangle = supported ? '▸' : '>';
    }
    const text = args.at(0);
    const logArgs = typeof text === 'string'
        ? [
            (0, strings_1.applyLinePrefix)(`${name ? `${name} ${pointingTriangle} ` : ''}${text}`, '[DEBUG] '),
            ...args.slice(1),
        ]
        : args;
    const { spinner = /*@__PURE__*/ require('./constants/spinner.js').default } = options;
    const wasSpinning = spinner.isSpinning;
    spinner.stop();
    const { logger } = /*@__PURE__*/ require('./logger.js');
    ReflectApply(logger.info, logger, logArgs);
    if (wasSpinning) {
        spinner.start();
    }
}
/* c8 ignore stop */
/**
 * Debug logging function.
 */
/*@__NO_SIDE_EFFECTS__*/
/* c8 ignore start - Debug utilities only used in development. */
function debugLogNs(namespacesOrOpts, ...args) {
    const options = extractOptions(namespacesOrOpts);
    const { namespaces } = options;
    if (!isEnabled(namespaces)) {
        return;
    }
    const { spinner = /*@__PURE__*/ require('./constants/spinner.js').default } = options;
    const wasSpinning = spinner.isSpinning;
    spinner.stop();
    ReflectApply(customLog, undefined, args);
    if (wasSpinning) {
        spinner.start();
    }
}
/* c8 ignore stop */
/**
 * Check if debug mode is enabled.
 */
/*@__NO_SIDE_EFFECTS__*/
/* c8 ignore start - Debug utilities only used in development. */
function isDebugNs(namespaces) {
    return ENV_1.SOCKET_CLI_DEBUG && isEnabled(namespaces);
}
/* c8 ignore stop */
/**
 * Simple debug check based on DEBUG environment variable.
 */
/*@__NO_SIDE_EFFECTS__*/
/* c8 ignore start - Debug utilities only used in development. */
function isDebugSimple() {
    const debug = process.env['DEBUG'];
    if (!debug || debug === '' || debug === '0' || debug === 'false') {
        return false;
    }
    return true;
}
/* c8 ignore stop */
/**
 * Simple debug log that logs to console when DEBUG is set.
 */
/*@__NO_SIDE_EFFECTS__*/
/* c8 ignore start - Debug utilities only used in development. */
function debugLogSimple(...args) {
    if (isDebugSimple()) {
        console.log(...args);
    }
}
/* c8 ignore stop */
/**
 * Simple debug dir that logs object to console when DEBUG is set.
 */
/*@__NO_SIDE_EFFECTS__*/
/* c8 ignore start - Debug utilities only used in development. */
function debugDirSimple(obj, options) {
    if (isDebugSimple()) {
        console.dir(obj, options || { depth: null, colors: true });
    }
}
/* c8 ignore stop */
/**
 * Simple debug function that creates a namespaced debug logger.
 */
/*@__NO_SIDE_EFFECTS__*/
/* c8 ignore start - Debug utilities only used in development. */
function matchPattern(ns, pattern) {
    if (pattern === '*') {
        return true;
    }
    if (pattern.endsWith(':*')) {
        const prefix = pattern.slice(0, -1);
        return ns.startsWith(prefix);
    }
    if (pattern.endsWith('*')) {
        const prefix = pattern.slice(0, -1);
        return ns.startsWith(prefix);
    }
    return ns === pattern;
}
function debugFnSimple(namespace) {
    const log = (...args) => {
        const debug = process.env['DEBUG'] || '';
        // Parse debug patterns.
        const patterns = debug.split(',').map(p => p.trim());
        const negations = patterns
            .filter(p => p.startsWith('-'))
            .map(p => p.slice(1));
        const includes = patterns.filter(p => !p.startsWith('-'));
        // Check if namespace should be skipped.
        for (const neg of negations) {
            if (neg === namespace || matchPattern(namespace, neg)) {
                return;
            }
        }
        // Check if namespace should be included.
        let shouldLog = false;
        for (const inc of includes) {
            if (inc === '*' || inc === namespace || matchPattern(namespace, inc)) {
                shouldLog = true;
                break;
            }
        }
        if (shouldLog) {
            const timestamp = new Date().toISOString();
            console.log(`[${timestamp}] ${namespace}:`, ...args);
        }
    };
    log.enabled = false;
    return log;
}
/* c8 ignore stop */
/**
 * Create a debug logger similar to util.debuglog.
 */
/*@__NO_SIDE_EFFECTS__*/
/* c8 ignore start - Debug utilities only used in development. */
function debuglog(section) {
    const log = (...args) => {
        if (isDebugSimple()) {
            console.log(`[${section}]`, ...args);
        }
    };
    return log;
}
/* c8 ignore stop */
/**
 * Create a debug timer.
 */
/*@__NO_SIDE_EFFECTS__*/
/* c8 ignore start - Debug utilities only used in development. */
function debugtime(section) {
    const timers = new Map();
    const timer = (label) => {
        if (isDebugSimple()) {
            console.log(`[${section}] ${label}`);
        }
    };
    timer.start = (label) => {
        if (isDebugSimple()) {
            timers.set(label, Date.now());
            console.log(`[${section}] ${label}: start`);
        }
    };
    timer.end = (label) => {
        if (isDebugSimple()) {
            const start = timers.get(label);
            if (start) {
                const duration = Date.now() - start;
                console.log(`[${section}] ${label}: ${duration}ms`);
                timers.delete(label);
            }
        }
    };
    return timer;
}
//# sourceMappingURL=debug.js.map