/*!
 * Copyright (C) Microsoft Corporation. All rights reserved.
 */
import { getEnvironmentByName, initializePlayerServices } from '@microsoft/power-apps-actions';
import { randomUUID } from 'crypto';
import packageJson from '../../package.json' with { type: 'json' };
import { printError } from '../Utils/ConsoleOutput.js';
import { ConsoleWriter } from './ConsoleWriter.js';
import { EUGeoRegions } from './Constants.js';
import { resolveUserTelemetrySettings } from './LoggerSettings.js';
import { OneDSWriter } from './OneDSWriter.js';
/**
 * Utility method to create a Scenario
 *
 * @param {ITelemetryWriter[]} telemetryWriters
 * @param {string} name
 * @param {object} [data]
 * @returns {Scenario}
 */
function createScenarioLogger(telemetryWriters, name, data) {
    const scenarioGuid = randomUUID();
    const _start = Date.now();
    try {
        telemetryWriters.forEach((writer) => writer.startScenario(name, { scenarioGuid, ...data, scenarioStartTime: _start }));
    }
    catch {
        // No-op. Telemetry failures should not block CLI operations
    }
    const base = {
        scenarioId: scenarioGuid,
        complete: (completeData) => {
            try {
                telemetryWriters.forEach((writer) => writer.completeScenario(name, {
                    scenarioGuid,
                    elapsedTime: Date.now() - _start,
                    totalElapsedTime: Date.now() - _start,
                    ...completeData,
                }));
            }
            catch {
                // No-op. Telemetry failures should not block CLI operations
            }
        },
        failure: (failureData) => {
            try {
                telemetryWriters.forEach((writer) => writer.scenarioFailed(name, {
                    scenarioGuid,
                    elapsedTime: Date.now() - _start,
                    totalElapsedTime: Date.now() - _start,
                    ...failureData,
                }));
            }
            catch {
                // No-op. Telemetry failures should not block CLI operations
            }
        },
        completeWithError: (dataWithErr) => {
            try {
                telemetryWriters.forEach((writer) => writer.scenarioCompletedWithError(name, {
                    scenarioGuid,
                    elapsedTime: Date.now() - _start,
                    totalElapsedTime: Date.now() - _start,
                    ...dataWithErr,
                }));
            }
            catch {
                // No-op. Telemetry failures should not block CLI operations
            }
        },
    };
    base._start = _start;
    return base;
}
/**
 * Logger implementation for the CLI
 * The logger depends on the CLISettings, HttpClient and authenticationProvider to initialize the OneDS writer
 */
export class CliLogger {
    _telemetryWriters = [];
    _oneDSConfig;
    constructor(telemetryWriters) {
        this._telemetryWriters = telemetryWriters;
    }
    static async create(cliSettings, httpClient) {
        const environmentId = cliSettings.appConfig?.environmentId;
        const region = cliSettings.appConfig?.region;
        const appId = cliSettings.appConfig?.appId;
        const sessionId = randomUUID();
        const telemetryWriters = [];
        const userTelemetrySettings = resolveUserTelemetrySettings();
        const addConsoleWriter = () => telemetryWriters.push(new ConsoleWriter());
        if (userTelemetrySettings.consoleOnly) {
            addConsoleWriter();
            return new CliLogger(telemetryWriters);
        }
        if (userTelemetrySettings.outputToConsole) {
            addConsoleWriter();
        }
        const instance = new CliLogger(telemetryWriters);
        if (userTelemetrySettings.enabled && region && environmentId) {
            // Store config for deferred initialization via initializeTelemetry()
            instance._oneDSConfig = {
                sessionId,
                region,
                environmentId,
                appId,
                httpClient,
                cliSettings,
            };
        }
        return instance;
    }
    /**
     * Initialize OneDS telemetry after authentication is ready.
     * Must be called after authenticationProvider.initAsync() completes.
     */
    async initializeTelemetry(authenticationProvider) {
        if (!this._oneDSConfig) {
            return;
        }
        const { sessionId, region, environmentId, appId, httpClient, cliSettings } = this._oneDSConfig;
        this._oneDSConfig = undefined;
        try {
            // Initialize player services to get environment metadata
            initializePlayerServices({
                httpClient,
                environmentName: cliSettings.appConfig?.environmentId || 'default',
                region: cliSettings.appConfig?.region || 'prod',
                // eslint-disable-next-line @typescript-eslint/no-explicit-any
            });
            const metadata = await getEnvironmentByName(environmentId);
            let telemetryLocation = 'global';
            if (metadata?.properties?.location && EUGeoRegions.has(metadata.properties.location)) {
                telemetryLocation = 'eu';
            }
            this._telemetryWriters.push(new OneDSWriter(sessionId, region, telemetryLocation, environmentId, appId ?? '', metadata?.properties?.cluster?.geoShortName, packageJson.version, cliSettings.source));
        }
        catch (error) {
            printError(`CliLogger: failed to initialize OneDS telemetry writer: ${String(error)}`);
        }
        if (authenticationProvider.getUserTenantId()) {
            // At this point if the auth provider has fetched a token, we can set the tenantId dimension
            this.setCustomDimension('tenantId', authenticationProvider.getUserTenantId());
        }
    }
    setCustomDimension(_key, _value) {
        try {
            if (!_key || !_value) {
                return;
            }
            this._telemetryWriters.forEach((writer) => {
                writer.setCustomDimension(_key, _value);
            });
        }
        catch {
            // No-op. Telemetry failures should not block CLI operations
        }
    }
    trackActivityEvent(eventName, eventData) {
        try {
            if (this._telemetryWriters.length === 0) {
                return;
            }
            this._telemetryWriters.forEach((writer) => writer.trackActivityEvent(eventName, eventData));
        }
        catch {
            // No-op. Telemetry failures should not block CLI operations
        }
    }
    trackErrorEvent(eventName, eventData) {
        try {
            if (this._telemetryWriters.length === 0) {
                return;
            }
            this._telemetryWriters.forEach((writer) => writer.trackErrorEvent(eventName, eventData));
        }
        catch {
            // No-op. Telemetry failures should not block CLI operations
        }
    }
    trackScenario(eventName, eventData) {
        try {
            if (this._telemetryWriters.length === 0) {
                // Return a no-op scenario so callers don't have to check telemetry state
                return {
                    scenarioId: 'disabled',
                    complete: () => undefined,
                    failure: () => undefined,
                    completeWithError: () => undefined,
                };
            }
            return createScenarioLogger(this._telemetryWriters, eventName, eventData);
        }
        catch {
            // No-op. Telemetry failures should not block CLI operations
            return {
                scenarioId: 'error',
                complete: () => undefined,
                failure: () => undefined,
                completeWithError: () => undefined,
            };
        }
    }
    stringifyError(err) {
        if (!err) {
            return undefined;
        }
        if (err instanceof Error) {
            return `${err.name}: ${err.message}${err.stack ? '\n' + err.stack : ''}`;
        }
        try {
            return JSON.stringify(err);
        }
        catch {
            return String(err);
        }
    }
    flush() {
        return Promise.all(this._telemetryWriters.map((writer) => writer.flush())).then(() => undefined);
    }
}
//# sourceMappingURL=CliLogger.js.map