/*!
 * Copyright (C) Microsoft Corporation. All rights reserved.
 */
import { generateGuid } from '../utils/GuidUtils.js';
import { stringifyError } from './stringifyError.js';
import { ScenarioResults, TelemetryEventNames } from './TelemetryTypes.js';
const severityOrder = {
    verbose: 0,
    info: 1,
    warning: 2,
    error: 3,
};
/**
 * Structured logger with canonical event names, severity filtering,
 * sequence numbering, and scenario tracking.
 * No-op safe when no provider is given.
 */
export class Logger {
    provider;
    minSeverity;
    sequence = 0;
    constructor(config) {
        this.provider = config?.provider;
        this.minSeverity = config?.provider?.minSeverity ?? 'verbose';
    }
    trackActivityEvent(name, properties, eventName) {
        this.emit('info', eventName ?? TelemetryEventNames.Activity, name, properties);
    }
    trackVerboseEvent(name, properties, eventName) {
        this.emit('verbose', eventName ?? TelemetryEventNames.Activity, name, properties);
    }
    trackErrorEvent(name, properties, eventName) {
        this.emit('error', eventName ?? TelemetryEventNames.Error, name, properties);
    }
    trackScenario(name, properties) {
        const startTime = typeof performance !== 'undefined' ? performance.now() : Date.now();
        const scenarioGuid = generateGuid();
        const scenarioProps = { ...properties, scenarioName: name, scenarioGuid };
        this.emit('info', TelemetryEventNames.StartScenario, name, scenarioProps);
        return {
            complete: (extraProps) => {
                const duration = (typeof performance !== 'undefined' ? performance.now() : Date.now()) - startTime;
                this.emit('info', TelemetryEventNames.EndScenario, name, {
                    ...scenarioProps,
                    ...extraProps,
                    scenarioResult: ScenarioResults.Success,
                    duration,
                });
            },
            completeWithError: (extraProps) => {
                const duration = (typeof performance !== 'undefined' ? performance.now() : Date.now()) - startTime;
                this.emit('warning', TelemetryEventNames.EndScenario, name, {
                    ...scenarioProps,
                    ...extraProps,
                    scenarioResult: ScenarioResults.SuccessWithErrors,
                    duration,
                });
            },
            fail: (error, extraProps) => {
                const duration = (typeof performance !== 'undefined' ? performance.now() : Date.now()) - startTime;
                this.emit('error', TelemetryEventNames.EndScenario, name, {
                    ...scenarioProps,
                    ...extraProps,
                    scenarioResult: ScenarioResults.Failed,
                    error: error !== undefined ? stringifyError(error) : undefined,
                    duration,
                });
            },
        };
    }
    setDefaultProperty(name, value) {
        this.provider?.setDefaultProperty(name, value);
    }
    identifyUser(identity) {
        this.provider?.identifyUser(identity);
    }
    get sessionId() {
        return this.provider?.sessionId;
    }
    set sessionId(value) {
        if (this.provider) {
            this.provider.sessionId = value;
        }
    }
    async flush() {
        await this.provider?.flush();
    }
    shouldLog(severity) {
        return severityOrder[severity] >= severityOrder[this.minSeverity];
    }
    emit(severity, eventName, operationName, properties) {
        if (!this.provider || !this.shouldLog(severity))
            return;
        const flatProps = flattenProperties(properties);
        flatProps.operationName = operationName;
        this.provider.track({
            eventName,
            timestamp: new Date().toISOString(),
            severity,
            sequenceNumber: ++this.sequence,
            duration: typeof flatProps.duration === 'number' ? flatProps.duration : undefined,
            properties: flatProps,
        });
    }
}
/** Convert Record<string, unknown> to Record<string, string | number | boolean> by JSON-stringifying non-primitives. */
function flattenProperties(properties) {
    const result = {};
    if (!properties)
        return result;
    for (const [key, value] of Object.entries(properties)) {
        if (value === undefined)
            continue;
        if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
            result[key] = value;
        }
        else {
            result[key] = JSON.stringify(value);
        }
    }
    return result;
}
//# sourceMappingURL=Logger.js.map