import * as Media from '@webex/internal-media-core';
import { Mutex } from 'async-mutex';
import { METHOD_START_MESSAGE } from '../common/constants';
import { filterMobiusUris, handleCallingClientErrors, normalizeMobiusUris, isValidServiceDomain, uploadLogs, validateServiceData, } from '../common/Utils';
import { LOGGER } from '../Logger/types';
import SDKConnector from '../SDKConnector';
import { Eventing } from '../Events/impl';
import { MOBIUS_EVENT_KEYS, SessionType, CALLING_CLIENT_EVENT_KEYS, } from '../Events/types';
import { ServiceIndicator, ALLOWED_SERVICES, HTTP_METHODS, RegistrationStatus, } from '../common/types';
import { MobiusEventType } from './calling/types';
import log from '../Logger';
import { getCallManager } from './calling/callManager';
import { CALLING_CLIENT_FILE, CALLS_CLEARED_HANDLER_UTIL, CALLING_USER_AGENT, CISCO_DEVICE_URL, DISCOVERY_URL, GET_MOBIUS_SERVERS_UTIL, SPARK_USER_AGENT, URL_ENDPOINT, API_V1, METHODS, NETWORK_FLAP_TIMEOUT, DEVICES_ENDPOINT_RESOURCE, WCC_CALLING_RTMS_DOMAIN, } from './constants';
import Line from './line';
import { METRIC_EVENT, REG_ACTION, METRIC_TYPE, CONNECTION_ACTION, MOBIUS_SERVER_ACTION, MOBIUS_SOCKET_ACTION, } from '../Metrics/types';
import { getMetricManager } from '../Metrics';
import windowsChromiumIceWarmup from './windowsChromiumIceWarmupUtils';
import { APIRequest } from './utils/request';
export class CallingClient extends Eventing {
    sdkConnector;
    webex;
    mutex;
    callManager;
    metricManager;
    sdkConfig;
    serviceData;
    primaryMobiusUris;
    backupMobiusUris;
    primaryWssMobiusUris;
    backupWssMobiusUris;
    mobiusClusters;
    mobiusHost;
    mediaEngine;
    lineDict = {};
    apiRequest;
    isNetworkDown = false;
    networkDownTimestamp = '';
    networkUpTimestamp = '';
    mercuryDownTimestamp = '';
    mercuryUpTimestamp = '';
    constructor(webex, config) {
        super();
        this.sdkConnector = SDKConnector;
        if (!this.sdkConnector.getWebex()) {
            SDKConnector.setWebex(webex);
            if (config?.logger?.level && webex.logger.config) {
                webex.logger.config.level = config.logger.level;
            }
            log.setWebexLogger(webex.logger);
        }
        this.mutex = new Mutex();
        this.webex = this.sdkConnector.getWebex();
        this.sdkConfig = config;
        this.serviceData = this.sdkConfig?.serviceData?.indicator
            ? this.sdkConfig.serviceData
            : { indicator: ServiceIndicator.CALLING, domain: '' };
        const logLevel = this.sdkConfig?.logger?.level ? this.sdkConfig.logger.level : LOGGER.ERROR;
        log.setLogger(logLevel, CALLING_CLIENT_FILE);
        validateServiceData(this.serviceData);
        this.callManager = getCallManager(this.webex, this.serviceData.indicator);
        this.metricManager = getMetricManager(this.webex, this.serviceData.indicator);
        this.mediaEngine = Media;
        const adaptedLogger = {
            log: (...args) => webex.logger.log(args.join(' : ')),
            error: (...args) => webex.logger.error(args.join(' : ')),
            warn: (...args) => webex.logger.warn(args.join(' : ')),
            info: (...args) => webex.logger.info(args.join(' : ')),
            trace: (...args) => webex.logger.trace(args.join(' : ')),
            debug: (...args) => webex.logger.debug(args.join(' : ')),
        };
        this.mediaEngine.setLogger(adaptedLogger);
        this.primaryMobiusUris = [];
        this.backupMobiusUris = [];
        this.primaryWssMobiusUris = [];
        this.backupWssMobiusUris = [];
        this.mobiusClusters = this.webex.internal.services.getMobiusClusters();
        this.mobiusHost = '';
        this.apiRequest = APIRequest.getInstance({ webex: this.webex });
        this.registerSessionsListener();
        this.registerCallsClearedListener();
    }
    async init() {
        const loggerContext = {
            file: CALLING_CLIENT_FILE,
            method: METHODS.INIT,
        };
        log.info(METHOD_START_MESSAGE, loggerContext);
        if (typeof window !== 'undefined' && window?.navigator?.userAgent) {
            const ua = window.navigator.userAgent;
            if (ua.toLowerCase().includes('windows')) {
                log.info('Starting ICE warmup for Windows Chromium based browser', {
                    file: CALLING_CLIENT_FILE,
                    method: 'init',
                });
                try {
                    await windowsChromiumIceWarmup({
                        iceServers: [],
                        timeoutMs: 1000,
                    });
                    log.info(`ICE warmup completed`, {
                        file: CALLING_CLIENT_FILE,
                        method: 'init',
                    });
                }
                catch (err) {
                    log.warn(`ICE warmup failed: ${err}`, {
                        file: CALLING_CLIENT_FILE,
                        method: 'init',
                    });
                }
            }
        }
        await this.getMobiusServers();
        if (this.apiRequest.isSocketEnabled()) {
            await this.connectToMobiusSocket();
            this.apiRequest.registerMobiusSocketListener(this.handleMobiusAsyncEvent);
        }
        if (this.serviceData.indicator === ServiceIndicator.CONTACT_CENTER &&
            !this.serviceData.domain) {
            const rtmsDomain = this.getRTMSDomain();
            this.serviceData.domain = rtmsDomain;
            if (this.sdkConfig?.serviceData) {
                this.sdkConfig.serviceData.domain = this.serviceData.domain;
            }
        }
        if (!isValidServiceDomain(this.serviceData)) {
            throw new Error('Invalid service domain.');
        }
        await this.createLine();
        this.setupNetworkEventListeners();
        log.log('CallingClient initialization complete', loggerContext);
    }
    getRTMSDomain() {
        log.info('Fetching RTMS domain from service catalog', {
            file: CALLING_CLIENT_FILE,
            method: METHODS.GET_RTMS_DOMAIN,
        });
        try {
            const rtmsURL = this.webex.internal.services.get(WCC_CALLING_RTMS_DOMAIN);
            const url = new URL(rtmsURL);
            log.info(`RTMS domain resolved from catalog: ${url.hostname}`, {
                file: CALLING_CLIENT_FILE,
                method: METHODS.GET_RTMS_DOMAIN,
            });
            return url.hostname;
        }
        catch (error) {
            log.warn(`Failed to fetch RTMS domain from service catalog: ${error}`, {
                file: CALLING_CLIENT_FILE,
                method: METHODS.GET_RTMS_DOMAIN,
            });
            return '';
        }
    }
    async checkNetworkReachability() {
        try {
            const controller = new AbortController();
            const timeoutId = setTimeout(() => controller.abort(), 3000);
            await fetch('https://www.google.com/generate_204', {
                method: 'GET',
                cache: 'no-cache',
                mode: 'no-cors',
                signal: controller.signal,
            });
            clearTimeout(timeoutId);
            return true;
        }
        catch (error) {
            log.warn(`Network connectivity probe failed: ${error}`, {
                file: CALLING_CLIENT_FILE,
                method: 'pingExternal',
            });
            return false;
        }
    }
    async checkCallStatus() {
        const loggerContext = {
            file: CALLING_CLIENT_FILE,
            method: 'checkCallStatus',
        };
        const calls = Object.values(this.callManager.getActiveCalls());
        for (const call of calls) {
            call
                .postStatus()
                .then(() => {
                log.info(`Call is active`, loggerContext);
            })
                .catch((err) => {
                log.warn(`Call Keepalive failed: ${err}`, loggerContext);
                call.sendCallStateMachineEvt({ type: 'E_SEND_CALL_DISCONNECT' });
            });
        }
    }
    handleNetworkOffline = async () => {
        this.networkDownTimestamp = new Date().toISOString();
        this.isNetworkDown = !(await this.checkNetworkReachability());
        log.warn(`Network has gone down, wait for it to come back up`, {
            file: CALLING_CLIENT_FILE,
            method: METHODS.NETWORK_OFFLINE,
        });
        if (this.isNetworkDown) {
            const line = Object.values(this.lineDict)[0];
            line.registration.clearKeepaliveTimer();
        }
    };
    handleNetworkOnline = () => {
        log.info(METHOD_START_MESSAGE, {
            file: CALLING_CLIENT_FILE,
            method: METHODS.NETWORK_ONLINE,
        });
        this.networkUpTimestamp = new Date().toISOString();
    };
    handleMercuryOffline = () => {
        log.warn(`Mercury down, waiting for connection to be up`, {
            file: CALLING_CLIENT_FILE,
            method: METHODS.MERCURY_OFFLINE,
        });
        this.mercuryDownTimestamp = new Date().toISOString();
        this.metricManager.submitConnectionMetrics(METRIC_EVENT.CONNECTION_ERROR, CONNECTION_ACTION.MERCURY_DOWN, METRIC_TYPE.BEHAVIORAL, this.mercuryDownTimestamp, this.mercuryUpTimestamp);
    };
    handleMercuryOnline = async () => {
        log.info(METHOD_START_MESSAGE, {
            file: CALLING_CLIENT_FILE,
            method: METHODS.MERCURY_ONLINE,
        });
        this.mercuryUpTimestamp = new Date().toISOString();
        if (this.isNetworkDown) {
            const callCheckInterval = setInterval(async () => {
                if (!Object.keys(this.callManager.getActiveCalls()).length) {
                    clearInterval(callCheckInterval);
                    const line = Object.values(this.lineDict)[0];
                    if (line.getStatus() !== RegistrationStatus.IDLE) {
                        this.isNetworkDown = await line.registration.handleConnectionRestoration(this.isNetworkDown);
                    }
                    else {
                        this.isNetworkDown = false;
                    }
                }
            }, NETWORK_FLAP_TIMEOUT);
            if (Object.keys(this.callManager.getActiveCalls()).length) {
                await this.checkCallStatus();
            }
            this.metricManager.submitConnectionMetrics(METRIC_EVENT.CONNECTION_ERROR, CONNECTION_ACTION.NETWORK_FLAP, METRIC_TYPE.BEHAVIORAL, this.networkDownTimestamp, this.networkUpTimestamp);
        }
        else {
            if (Object.keys(this.callManager.getActiveCalls()).length) {
                await this.checkCallStatus();
            }
            this.metricManager.submitConnectionMetrics(METRIC_EVENT.CONNECTION_ERROR, CONNECTION_ACTION.MERCURY_UP, METRIC_TYPE.BEHAVIORAL, this.mercuryDownTimestamp, this.mercuryUpTimestamp);
        }
    };
    setupNetworkEventListeners() {
        if (typeof window !== 'undefined' && window.addEventListener) {
            window.addEventListener('online', this.handleNetworkOnline);
            window.addEventListener('offline', this.handleNetworkOffline);
        }
        this.webex.internal.mercury.on('offline', () => {
            this.handleMercuryOffline();
        });
        this.webex.internal.mercury.on('online', () => {
            this.handleMercuryOnline();
        });
    }
    async getClientRegionInfo() {
        let abort;
        log.info(METHOD_START_MESSAGE, {
            file: CALLING_CLIENT_FILE,
            method: METHODS.GET_CLIENT_REGION_INFO,
        });
        const regionInfo = {};
        try {
            const response = await this.webex.request({
                uri: `${DISCOVERY_URL}`,
                method: HTTP_METHODS.GET,
                addAuthHeader: false,
                headers: {
                    [SPARK_USER_AGENT]: null,
                },
            });
            const clientRegionInfo = response.body;
            regionInfo.clientRegion = clientRegionInfo?.clientRegion || '';
            regionInfo.countryCode = clientRegionInfo?.countryCode || '';
            log.log(`Successfully fetched Client region info: ${regionInfo.clientRegion}, countryCode: ${regionInfo.countryCode}, and response trackingid: ${response?.headers?.trackingid}`, {
                file: CALLING_CLIENT_FILE,
                method: METHODS.GET_CLIENT_REGION_INFO,
            });
            this.metricManager.submitRegionInfoMetric(METRIC_EVENT.MOBIUS_DISCOVERY, MOBIUS_SERVER_ACTION.REGION_INFO, METRIC_TYPE.BEHAVIORAL, this.mobiusHost, clientRegionInfo.clientRegion, clientRegionInfo.countryCode, response?.headers?.trackingid ?? '');
        }
        catch (err) {
            log.error(`Failed to get client region info: ${JSON.stringify(err)}`, {
                method: METHODS.GET_CLIENT_REGION_INFO,
                file: CALLING_CLIENT_FILE,
            });
            abort = await handleCallingClientErrors(err, (clientError) => {
                this.metricManager.submitRegistrationMetric(METRIC_EVENT.REGISTRATION_ERROR, REG_ACTION.REGISTER, METRIC_TYPE.BEHAVIORAL, GET_MOBIUS_SERVERS_UTIL, 'UNKNOWN', err.headers?.trackingId ?? '', undefined, clientError);
                this.emit(CALLING_CLIENT_EVENT_KEYS.ERROR, clientError);
            }, { method: GET_MOBIUS_SERVERS_UTIL, file: CALLING_CLIENT_FILE });
            regionInfo.clientRegion = '';
            regionInfo.countryCode = '';
            if (abort) {
                await uploadLogs();
                return regionInfo;
            }
        }
        return regionInfo;
    }
    async getMobiusServers() {
        log.info(METHOD_START_MESSAGE, {
            file: CALLING_CLIENT_FILE,
            method: METHODS.GET_MOBIUS_SERVERS,
        });
        let useDefault = false;
        let clientRegion;
        let countryCode;
        if (this.sdkConfig?.discovery?.country && this.sdkConfig?.discovery?.region) {
            log.log('Updating region and country from the SDK config', {
                file: CALLING_CLIENT_FILE,
                method: GET_MOBIUS_SERVERS_UTIL,
            });
            clientRegion = this.sdkConfig?.discovery?.region;
            countryCode = this.sdkConfig?.discovery?.country;
            this.mobiusHost =
                this.webex.internal.services._serviceUrls?.mobius ||
                    this.webex.internal.services.get(this.webex.internal.services._activeServices.mobius);
        }
        else {
            log.log('Updating region and country through Region discovery', {
                file: CALLING_CLIENT_FILE,
                method: GET_MOBIUS_SERVERS_UTIL,
            });
            const regionInfo = await this.getClientRegionInfo();
            clientRegion = regionInfo.clientRegion;
            countryCode = regionInfo.countryCode;
        }
        if (clientRegion && countryCode) {
            log.log(`Found Region: ${clientRegion} and country: ${countryCode}, going to fetch Mobius server`, {
                file: CALLING_CLIENT_FILE,
                method: GET_MOBIUS_SERVERS_UTIL,
            });
            for (const mobius of this.mobiusClusters) {
                if (mobius.host) {
                    this.mobiusHost = `https://${mobius.host}${API_V1}`;
                }
                else {
                    this.mobiusHost = mobius;
                }
                try {
                    const response = await this.webex.request({
                        uri: `${this.mobiusHost}${URL_ENDPOINT}?regionCode=${clientRegion}&countryCode=${countryCode}`,
                        method: HTTP_METHODS.GET,
                        headers: {
                            [CISCO_DEVICE_URL]: this.webex.internal.device.url,
                            [SPARK_USER_AGENT]: CALLING_USER_AGENT,
                        },
                        service: ALLOWED_SERVICES.MOBIUS,
                    });
                    log.log(`Mobius Server found for the region. Response trackingId: ${response?.headers?.trackingid}`, {
                        file: CALLING_CLIENT_FILE,
                        method: GET_MOBIUS_SERVERS_UTIL,
                    });
                    const mobiusServers = response.body;
                    this.metricManager.submitMobiusServersMetric(METRIC_EVENT.MOBIUS_DISCOVERY, MOBIUS_SERVER_ACTION.MOBIUS_SERVERS, METRIC_TYPE.BEHAVIORAL, mobiusServers, response?.headers?.trackingid ?? '');
                    const mobiusUris = filterMobiusUris(mobiusServers, this.mobiusHost);
                    this.primaryMobiusUris = mobiusUris.primary;
                    this.backupMobiusUris = mobiusUris.backup;
                    this.primaryWssMobiusUris = mobiusUris.primaryWss;
                    this.backupWssMobiusUris = mobiusUris.backupWss;
                    log.log(`Final list of Mobius Servers, primary: ${mobiusUris.primary} and backup: ${mobiusUris.backup}`, {
                        file: CALLING_CLIENT_FILE,
                        method: GET_MOBIUS_SERVERS_UTIL,
                    });
                    break;
                }
                catch (err) {
                    log.error(`Failed to get Mobius servers: ${JSON.stringify(err)}`, {
                        method: METHODS.GET_MOBIUS_SERVERS,
                        file: CALLING_CLIENT_FILE,
                    });
                    const abort = await handleCallingClientErrors(err, (clientError) => {
                        this.metricManager.submitRegistrationMetric(METRIC_EVENT.REGISTRATION_ERROR, REG_ACTION.REGISTER, METRIC_TYPE.BEHAVIORAL, GET_MOBIUS_SERVERS_UTIL, 'UNKNOWN', err.headers?.trackingId ?? '', undefined, clientError);
                        this.emit(CALLING_CLIENT_EVENT_KEYS.ERROR, clientError);
                    }, { method: GET_MOBIUS_SERVERS_UTIL, file: CALLING_CLIENT_FILE });
                    if (abort) {
                        useDefault = true;
                        await uploadLogs();
                        break;
                    }
                }
            }
        }
        else {
            useDefault = true;
        }
        if (useDefault) {
            log.warn(`Couldn't resolve the region and country code. Defaulting to the catalog entries to discover mobius servers`, {
                file: CALLING_CLIENT_FILE,
                method: GET_MOBIUS_SERVERS_UTIL,
            });
            this.mobiusHost = `https://${this.mobiusClusters[0].host}${API_V1}`;
            this.primaryMobiusUris = [`${this.mobiusHost}${URL_ENDPOINT}`];
        }
    }
    async connectToMobiusSocket() {
        const loggerContext = {
            file: CALLING_CLIENT_FILE,
            method: METHODS.CONNECT_TO_MOBIUS_SOCKET,
        };
        log.info(METHOD_START_MESSAGE, loggerContext);
        if (!this.primaryWssMobiusUris.length && !this.backupWssMobiusUris.length) {
            log.warn('No WSS URIs available from Mobius discovery, skipping socket connection', loggerContext);
            return;
        }
        if (this.primaryWssMobiusUris.length) {
            log.log(`Attempting Mobius socket connection using primary WSS URIs (${this.primaryWssMobiusUris.length} available)`, loggerContext);
            for (const wssUri of this.primaryWssMobiusUris) {
                try {
                    log.log(`Trying primary WSS URI: ${wssUri}`, loggerContext);
                    await this.apiRequest.connectToMobiusSocket(wssUri);
                    log.log(`Successfully connected to Mobius socket on primary WSS URI: ${wssUri}`, loggerContext);
                    return;
                }
                catch (err) {
                    log.warn(`Primary WSS URI connection failed for ${wssUri}: ${err}`, loggerContext);
                }
            }
            log.warn('All primary WSS URI connection attempts failed', loggerContext);
        }
        else {
            log.warn('No primary WSS URIs available, skipping to backup', loggerContext);
        }
        if (this.backupWssMobiusUris.length) {
            log.log(`Attempting Mobius socket connection using backup WSS URIs (${this.backupWssMobiusUris.length} available)`, loggerContext);
            for (const wssUri of this.backupWssMobiusUris) {
                try {
                    log.log(`Trying backup WSS URI: ${wssUri}`, loggerContext);
                    await this.apiRequest.connectToMobiusSocket(wssUri);
                    log.log(`Successfully connected to Mobius socket on backup WSS URI: ${wssUri}`, loggerContext);
                    return;
                }
                catch (err) {
                    log.warn(`Backup WSS URI connection failed for ${wssUri}: ${err}`, loggerContext);
                }
            }
            log.warn('All backup WSS URI connection attempts failed', loggerContext);
        }
        else {
            log.warn('No backup WSS URIs available', loggerContext);
        }
        log.warn('All Mobius socket connection attempts exhausted for both primary and backup, continuing without socket', loggerContext);
    }
    handleMobiusAsyncEvent = async (event) => {
        const loggerContext = {
            file: CALLING_CLIENT_FILE,
            method: METHODS.HANDLE_MOBIUS_ASYNC_EVENT,
        };
        const eventType = event?.data.eventType;
        log.trace(`Mobius async event received - eventType: ${eventType ?? 'undefined'}`, loggerContext);
        if (!eventType) {
            log.warn('Dropping unsupported mobius socket payload', loggerContext);
            return;
        }
        if (eventType === MobiusEventType.REGISTRATION_DOWN) {
            log.warn(`Received ${eventType} event from Mobius.`, loggerContext);
            const line = Object.values(this.lineDict)[0];
            if (!line) {
                log.warn('No line found, skipping registration down event', loggerContext);
                return;
            }
            await line.registration.handleRegistrationDownEvent(event);
            this.metricManager.submitMobiusSocketMetric(METRIC_EVENT.MOBIUS_SOCKET_ERROR, MOBIUS_SOCKET_ACTION.REGISTRATION_DOWN, METRIC_TYPE.BEHAVIORAL, undefined, event?.trackingId, undefined, eventType);
            return;
        }
        this.callManager.dequeueWsEvents(event);
        log.trace(`Mobius async event dispatched to CallManager - eventType: ${eventType}`, loggerContext);
    };
    registerCallsClearedListener() {
        log.info(METHOD_START_MESSAGE, {
            file: CALLING_CLIENT_FILE,
            method: METHODS.REGISTER_CALLS_CLEARED_LISTENER,
        });
        this.callManager.on(CALLING_CLIENT_EVENT_KEYS.ALL_CALLS_CLEARED, this.callsClearedHandler);
    }
    callsClearedHandler = async () => {
        log.info(METHOD_START_MESSAGE, {
            file: CALLING_CLIENT_FILE,
            method: METHODS.CALLS_CLEARED_HANDLER,
        });
        const { registration } = Object.values(this.lineDict)[0];
        if (!registration.isDeviceRegistered()) {
            await this.mutex.runExclusive(async () => {
                if (registration.isReconnectPending()) {
                    log.info('All calls cleared, reconnecting', {
                        file: CALLING_CLIENT_FILE,
                        method: CALLS_CLEARED_HANDLER_UTIL,
                    });
                    await registration.reconnectOnFailure(CALLS_CLEARED_HANDLER_UTIL);
                }
            });
        }
    };
    getLoggingLevel() {
        return log.getLogLevel();
    }
    getSDKConnector() {
        return this.sdkConnector;
    }
    registerSessionsListener() {
        log.info(METHOD_START_MESSAGE, {
            file: CALLING_CLIENT_FILE,
            method: METHODS.REGISTER_SESSIONS_LISTENER,
        });
        this.sdkConnector.registerListener(MOBIUS_EVENT_KEYS.CALL_SESSION_EVENT_INCLUSIVE, async (event) => {
            if (event && event.data.userSessions.userSessions) {
                const sessionArr = event?.data.userSessions.userSessions;
                if (sessionArr.length === 1) {
                    if (sessionArr[0].sessionType !== SessionType.WEBEX_CALLING) {
                        return;
                    }
                }
                for (let i = 0; i < sessionArr.length; i += 1) {
                    if (sessionArr[i].sessionType !== SessionType.WEBEX_CALLING) {
                        sessionArr.splice(i, 1);
                    }
                }
                this.emit(CALLING_CLIENT_EVENT_KEYS.USER_SESSION_INFO, event);
            }
        });
    }
    async createLine() {
        log.info(METHOD_START_MESSAGE, {
            file: CALLING_CLIENT_FILE,
            method: METHODS.CREATE_LINE,
        });
        const line = new Line(this.webex.internal.device.userId, this.webex.internal.device.url, this.mutex, this.apiRequest.isSocketEnabled()
            ? normalizeMobiusUris(this.primaryWssMobiusUris)
            : this.primaryMobiusUris, this.apiRequest.isSocketEnabled()
            ? normalizeMobiusUris(this.backupWssMobiusUris)
            : this.backupMobiusUris, this.getLoggingLevel(), this.serviceData, this.sdkConfig?.jwe);
        this.lineDict[line.lineId] = line;
    }
    getLines() {
        return this.lineDict;
    }
    async getDevices(userId) {
        const userid = userId || this.webex.internal.device.userId;
        if (!userid) {
            throw new Error('userId is required to fetch devices');
        }
        log.info(METHOD_START_MESSAGE, { file: CALLING_CLIENT_FILE, method: METHODS.GET_DEVICES });
        const mobiusUrls = [...this.primaryMobiusUris, ...this.backupMobiusUris];
        if (mobiusUrls.length === 0) {
            throw new Error('Mobius URLs are not available');
        }
        let finalError;
        for (const mobiusUrl of mobiusUrls) {
            const normalizedMobiusUrl = mobiusUrl.replace(/\/+$/, '/');
            const uri = `${normalizedMobiusUrl}${DEVICES_ENDPOINT_RESOURCE}?userid=${encodeURIComponent(userid)}`;
            try {
                const response = (await this.webex.request({
                    uri,
                    method: HTTP_METHODS.GET,
                    service: ALLOWED_SERVICES.MOBIUS,
                    headers: {
                        [CISCO_DEVICE_URL]: this.webex.internal.device.url,
                        [SPARK_USER_AGENT]: CALLING_USER_AGENT,
                    },
                }));
                if (response.statusCode !== 200) {
                    throw new Error(`API call failed with ${response.statusCode}`);
                }
                const body = response.body;
                Object.values(this.lineDict)[0].registration.setDeviceInfo(body);
                Object.values(this.lineDict)[0].registration.setActiveMobiusUrl(normalizedMobiusUrl);
                return body.devices ?? [];
            }
            catch (error) {
                finalError = error;
            }
        }
        log.error(`Failed to fetch devices for userId ${userId}: ${JSON.stringify(finalError)}`, {
            file: CALLING_CLIENT_FILE,
            method: METHODS.GET_DEVICES,
        });
        throw finalError;
    }
    getActiveCalls() {
        const activeCalls = {};
        const calls = this.callManager.getActiveCalls();
        Object.keys(calls).forEach((correlationId) => {
            const call = calls[correlationId];
            if (!activeCalls[call.lineId]) {
                activeCalls[call.lineId] = [];
            }
            activeCalls[call.lineId].push(call);
        });
        return activeCalls;
    }
    getConnectedCall() {
        let connectCall;
        const calls = this.callManager.getActiveCalls();
        Object.keys(calls).forEach((correlationId) => {
            if (calls[correlationId].isConnected() && !calls[correlationId].isHeld()) {
                connectCall = calls[correlationId];
            }
        });
        return connectCall;
    }
    async uploadLogs() {
        const result = await uploadLogs({}, true);
        if (!result) {
            throw new Error('Failed to upload logs: No response received.');
        }
        return result;
    }
}
export const createClient = async (webex, config) => {
    const callingClientInstance = new CallingClient(webex, config);
    await callingClientInstance.init();
    return callingClientInstance;
};
