"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.startAnalytics = startAnalytics;
exports.reportNxAddCommand = reportNxAddCommand;
exports.reportNxGenerateCommand = reportNxGenerateCommand;
exports.reportCommandRunEvent = reportCommandRunEvent;
exports.reportProjectGraphCreationEvent = reportProjectGraphCreationEvent;
exports.argsToQueryString = argsToQueryString;
exports.flushAnalytics = flushAnalytics;
const nx_json_1 = require("../config/nx-json");
const workspace_root_1 = require("../utils/workspace-root");
const versions_1 = require("../utils/versions");
const native_1 = require("../native");
const package_manager_1 = require("../utils/package-manager");
const semver_1 = require("semver");
const os = require("os");
const machine_id_cache_1 = require("../utils/machine-id-cache");
const is_ci_1 = require("../utils/is-ci");
const analytics_prompt_1 = require("../utils/analytics-prompt");
const db_connection_1 = require("../utils/db-connection");
// Conditionally import telemetry functions only on non-WASM platforms
let initializeTelemetry;
let flushTelemetry;
let trackEventNative;
let trackPageViewNative;
let getEventDimensions;
if (!native_1.IS_WASM) {
    const nativeModule = require('../native');
    initializeTelemetry = nativeModule.initializeTelemetry;
    flushTelemetry = nativeModule.flushTelemetry;
    trackEventNative = nativeModule.trackEvent;
    trackPageViewNative = nativeModule.trackPageView;
    getEventDimensions = nativeModule.getEventDimensions;
}
const customDimensions = native_1.IS_WASM ? null : (getEventDimensions?.() ?? null);
let _telemetryInitialized = false;
async function startAnalytics() {
    // Analytics not supported on WASM
    if (native_1.IS_WASM) {
        return;
    }
    if (!isAnalyticsEnabled()) {
        return;
    }
    const nxJson = (0, nx_json_1.readNxJson)(workspace_root_1.workspaceRoot);
    const workspaceId = (0, analytics_prompt_1.generateWorkspaceId)();
    if (!workspaceId) {
        // Not a git repo — no telemetry
        return;
    }
    const isNxCloud = !!(nxJson?.nxCloudId ?? nxJson?.nxCloudAccessToken);
    const userId = await (0, machine_id_cache_1.getCurrentMachineId)();
    const packageManagerInfo = getPackageManagerInfo();
    const nodeVersion = (0, semver_1.parse)(process.version);
    const nodeVersionString = nodeVersion
        ? `${nodeVersion.major}.${nodeVersion.minor}.${nodeVersion.patch}`
        : 'unknown';
    try {
        const dbConnection = (0, db_connection_1.getDbConnection)();
        initializeTelemetry(dbConnection, workspaceId, userId, versions_1.nxVersion, packageManagerInfo.name, packageManagerInfo.version, nodeVersionString, os.arch(), os.platform(), os.release(), !!(0, is_ci_1.isCI)(), isNxCloud);
        _telemetryInitialized = true;
        // Flush analytics automatically on process exit so every code path
        // is covered without needing explicit exitAndFlushAnalytics() calls.
        process.on('exit', () => {
            flushAnalytics();
        });
    }
    catch (error) {
        // If telemetry service fails to initialize, continue without it
        if (process.env.NX_VERBOSE_LOGGING === 'true') {
            console.log(`Failed to initialize telemetry: ${error.message}`);
        }
    }
}
function reportNxAddCommand(packageName, version) {
    reportCommandRunEvent('add', {
        [customDimensions.packageName]: packageName,
        [customDimensions.packageVersion]: version,
    });
}
function reportNxGenerateCommand(generator) {
    reportCommandRunEvent('generate', {
        [customDimensions.generatorName]: generator,
    });
}
function reportCommandRunEvent(command, parameters, args) {
    command = command === 'g' ? 'generate' : command;
    let pageLocation = command;
    if (args) {
        const qs = argsToQueryString(args);
        if (qs) {
            pageLocation = `${command}?${qs}`;
        }
    }
    trackPageView(command, pageLocation, parameters);
}
function reportProjectGraphCreationEvent(duration) {
    trackEvent(customDimensions.createProjectGraph, {
        [customDimensions.duration]: duration,
    });
}
const SKIP_ARGS_KEYS = new Set([
    '$0',
    '_',
    '__overrides_unparsed__',
    '__overrides__',
]);
// String args with fixed enum values that are safe to include in analytics.
// All boolean and number args are included automatically.
const ALLOWED_STRING_ARGS = new Set([
    'outputStyle',
    'type',
    'view',
    'access',
    'preset',
    'interactive',
    'printConfig',
    'resolveVersionPlans',
]);
function argsToQueryString(args) {
    const params = new URLSearchParams();
    for (const [key, value] of Object.entries(args)) {
        if (SKIP_ARGS_KEYS.has(key))
            continue;
        if (value === undefined || value === null)
            continue;
        if (typeof value === 'boolean' || typeof value === 'number') {
            params.append(key, String(value));
        }
        else if (typeof value === 'string' && ALLOWED_STRING_ARGS.has(key)) {
            params.append(key, value);
        }
        // All other types (strings, arrays, objects) are dropped
    }
    return params.toString();
}
function trackEvent(eventName, parameters) {
    if (_telemetryInitialized) {
        // Convert parameters to string map for Rust
        const stringParams = {};
        if (parameters) {
            for (const [key, value] of Object.entries(parameters)) {
                if (value !== undefined && value !== null) {
                    stringParams[key] = String(value);
                }
            }
        }
        // Fire and forget - synchronous call
        try {
            trackEventNative(eventName, stringParams);
        }
        catch {
            // Silently ignore errors
        }
    }
}
function trackPageView(pageTitle, pageLocation, parameters) {
    if (_telemetryInitialized) {
        // Convert parameters to string map for Rust
        const stringParams = {};
        if (parameters) {
            for (const [key, value] of Object.entries(parameters)) {
                if (value !== undefined && value !== null) {
                    stringParams[key] = String(value);
                }
            }
        }
        // Fire and forget - synchronous call
        try {
            trackPageViewNative(pageTitle, pageLocation, stringParams);
        }
        catch {
            // Silently ignore errors
        }
    }
}
function flushAnalytics() {
    if (_telemetryInitialized) {
        try {
            flushTelemetry();
        }
        catch (error) {
            // Failure to report analytics shouldn't crash the CLI
            if (process.env.NX_VERBOSE_LOGGING === 'true') {
                console.log(`Failed to flush telemetry: ${error.message}`);
            }
        }
    }
}
function getPackageManagerInfo() {
    const pm = (0, package_manager_1.detectPackageManager)();
    return {
        name: pm,
        version: (0, package_manager_1.getPackageManagerVersion)(pm),
    };
}
function isAnalyticsEnabled() {
    const nxJson = (0, nx_json_1.readNxJson)(workspace_root_1.workspaceRoot);
    return nxJson?.analytics === true;
}
