import Queue from 'queue';
import { v4 as uuidv4 } from 'uuid';
import version from '../../lib/version.js';
// Implements a compatible Analytics 2.0 API with custom options.
// https://segment.com/docs/connections/sources/catalog/libraries/website/javascript/
export class TelemetryClient {
    #queue;
    #anonymousId;
    #endpoint;
    #debug;
    #disabled;
    #loaded = false;
    #user = null;
    constructor({ endpoint = 'https://connect.getseam.com', debug = false, disabled = false, } = {}) {
        this.#queue = new Queue();
        this.#anonymousId = uuidv4();
        this.#endpoint = endpoint;
        this.#debug = debug;
        this.#disabled = disabled;
    }
    load({ endpoint, debug, disabled } = {}) {
        this.#log('load', { endpoint, debug, disabled });
        if (this.#loaded) {
            throw new Error('TelemetryClient already loaded. Call TelemetryClient.reset() first.');
        }
        if (endpoint != null)
            this.#endpoint = endpoint;
        if (debug != null)
            this.#debug = debug;
        if (disabled != null)
            this.#disabled = disabled;
        this.#queue.autostart = true;
        this.#queue.start((err) => {
            // eslint-disable-next-line no-console
            if (err != null && this.#debug)
                console.error(err);
        });
        this.#loaded = true;
    }
    reset() {
        this.#log('reset');
        this.#queue.autostart = false;
        this.#queue.end();
        this.#anonymousId = uuidv4();
        this.#user = null;
        this.#loaded = false;
    }
    debug(debug) {
        if (debug != null)
            this.#debug = debug;
        return this.#debug;
    }
    page(name, properties = {}) {
        this.#log('page', name, properties);
        this.#push({ type: 'page', name, properties });
    }
    screen(name, properties = {}) {
        this.#log('screen', name, properties);
        this.#push({ type: 'screen', name, properties });
    }
    track(event, properties = {}) {
        this.#log('track', event, properties);
        this.#push({ type: 'track', event, properties });
    }
    group(groupId, traits = {}) {
        this.#log('group', groupId, traits);
        this.#push({
            type: 'group',
            groupId,
            traits,
        });
    }
    identify(userId, traits = {}) {
        this.#log('identify', userId, traits);
        this.#anonymousId = null;
        if (this.#user?.userId !== userId) {
            this.#user = { userId, traits: {} };
        }
        this.#user = {
            userId,
            traits: {
                ...(this.#user?.traits ?? {}),
                ...traits,
            },
        };
        this.#push({
            type: 'identify',
            userId,
            traits: this.#user.traits,
        });
    }
    alias(userId, previousId) {
        const resolvedPreviousId = previousId ?? this.#user?.userId ?? this.#anonymousId;
        if (resolvedPreviousId == null) {
            throw new Error('Cannot resolve previous id');
        }
        this.#log('alias', userId, resolvedPreviousId);
        this.#push({
            type: 'alias',
            userId,
            previousId: resolvedPreviousId,
            anonymousId: undefined,
        });
    }
    get #context() {
        return {
            ...(this.#user?.traits == null ? {} : { traits: this.#user.traits }),
            app: {
                version: version ?? undefined,
                name: 
                // Assume if one of the elements is defined then this is loaded inside a web component.
                // This method will be inaccurate if the element bundle is loaded alongside
                // an app using the React components, however this use case is unlikely.
                // Choose seam-device-details as this component is unlikely to ever be removed.
                globalThis.customElements.get('seam-device-details') != null
                    ? '@seamapi/react/elements'
                    : '@seamapi/react',
            },
        };
    }
    #push = (message) => {
        if (this.#disabled)
            return;
        this.#queue.push(async () => {
            const payload = {
                userId: this.#user?.userId ?? undefined,
                anonymousId: this.#anonymousId ?? undefined,
                ...message,
                messageId: uuidv4(),
                timestamp: new Date().toISOString(),
                context: this.#context,
            };
            const response = await fetch(`${this.#endpoint}/internal/tlmtry`, {
                method: 'POST',
                body: JSON.stringify(payload),
                headers: { 'Content-Type': 'application/json' },
            });
            if (!response.ok) {
                throw new Error(`Telemetry request failed with ${response.status} ${response.statusText}`);
            }
        });
    };
    #log = (method, ...args) => {
        if (!this.#debug)
            return;
        const strArgs = args.length > 0 ? args.map((arg) => JSON.stringify(arg)).join(', ') : '';
        // eslint-disable-next-line no-console
        console.log(`TelemetryClient.${method}(${strArgs})`);
    };
}
//# sourceMappingURL=client.js.map