// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
import { ChatClient } from '@azure/communication-chat';
import { _getApplicationId } from "../../acs-ui-common/src";
import { ChatContext } from './ChatContext';
import { EventSubscriber } from './EventSubscriber';
import { chatThreadClientDeclaratify } from './StatefulChatThreadClient';
import { createDecoratedListThreads } from './iterators/createDecoratedListThreads';
import { getIdentifierKind } from '@azure/communication-common';
import { chatStatefulLogger } from './Logger';
const proxyChatClient = {
    get: function (chatClient, prop, receiver) {
        // skip receiver.context call to avoid recursive bugs
        if (prop === 'context') {
            return Reflect.get(chatClient, prop);
        }
        const context = receiver.context;
        switch (prop) {
            case 'createChatThread':
                {
                    return context.withAsyncErrorTeedToState(function (...args) {
                        return __awaiter(this, void 0, void 0, function* () {
                            const result = yield chatClient.createChatThread(...args);
                            const thread = result.chatThread;
                            if (thread) {
                                const [request] = args;
                                context.createThread(thread.id, {
                                    topic: request.topic
                                });
                            }
                            return result;
                        });
                    }, 'ChatClient.createChatThread');
                }
            case 'deleteChatThread':
                {
                    return context.withAsyncErrorTeedToState(function (...args) {
                        return __awaiter(this, void 0, void 0, function* () {
                            const result = yield chatClient.deleteChatThread(...args);
                            context.deleteThread(args[0]);
                            return result;
                        });
                    }, 'ChatClient.deleteChatThread');
                }
            case 'listChatThreads':
                {
                    return createDecoratedListThreads(chatClient, context);
                }
            case 'getChatThreadClient':
                {
                    return function (...args) {
                        const chatThreadClient = chatClient.getChatThreadClient(...args);
                        // TODO(prprabhu): Ensure that thread properties are fetched into the ChatContext at this point.
                        // A new thread might be created here, but the properties will never be fetched.
                        return chatThreadClientDeclaratify(chatThreadClient, context);
                    };
                }
            case 'startRealtimeNotifications':
                {
                    return context.withAsyncErrorTeedToState(function (...args) {
                        return __awaiter(this, void 0, void 0, function* () {
                            const ret = yield chatClient.startRealtimeNotifications(...args);
                            if (!receiver.eventSubscriber) {
                                receiver.eventSubscriber = new EventSubscriber(chatClient, context);
                            }
                            return ret;
                        });
                    }, 'ChatClient.startRealtimeNotifications');
                }
            case 'stopRealtimeNotifications':
                {
                    return context.withAsyncErrorTeedToState(function (...args) {
                        return __awaiter(this, void 0, void 0, function* () {
                            const ret = yield chatClient.stopRealtimeNotifications(...args);
                            if (receiver.eventSubscriber) {
                                receiver.eventSubscriber.unsubscribe();
                                receiver.eventSubscriber = undefined;
                            }
                            return ret;
                        });
                    }, 'ChatClient.stopRealtimeNotifications');
                }
            default:
                return Reflect.get(chatClient, prop);
        }
    }
};
/**
 * Creates a stateful ChatClient {@link StatefulChatClient} by proxying ChatClient
 * {@link @azure/communication-chat#ChatClient} with ProxyChatClient {@link ProxyChatClient} which then allows access
 * to state in a declarative way.
 *
 * @public
 */
export const createStatefulChatClient = (args, options) => {
    return _createStatefulChatClientInner(args, options);
};
/**
 * This inner function is used to allow injection of TelemetryImplementationHint without changing the public API.
 *
 * @internal
 */
export const _createStatefulChatClientInner = (args, options, telemetryImplementationHint = 'StatefulComponents') => {
    chatStatefulLogger.info(`Creating chat stateful client using library version: ${_getApplicationId(telemetryImplementationHint)}`);
    const tweakedOptions = Object.assign(Object.assign({}, options), { chatClientOptions: Object.assign(Object.assign({}, options === null || options === void 0 ? void 0 : options.chatClientOptions), { userAgentOptions: {
                userAgentPrefix: _getApplicationId(telemetryImplementationHint)
            } }) });
    return _createStatefulChatClientWithDeps(new ChatClient(args.endpoint, args.credential, tweakedOptions.chatClientOptions), args, tweakedOptions);
};
/**
 * Internal implementation of {@link createStatefulChatClient} for dependency injection.
 *
 * Used by tests. Should not be exported out of this package.
 * @internal
 */
export const _createStatefulChatClientWithDeps = (chatClient, args, options) => {
    const context = new ChatContext(options === null || options === void 0 ? void 0 : options.maxStateChangeListeners, args.credential, args.endpoint);
    let eventSubscriber;
    context.updateChatConfig(getIdentifierKind(args.userId), args.displayName);
    const proxy = new Proxy(chatClient, proxyChatClient);
    Object.defineProperty(proxy, 'context', {
        configurable: false,
        get: () => context
    });
    Object.defineProperty(proxy, 'eventSubscriber', {
        configurable: false,
        get: () => eventSubscriber,
        set: (val) => {
            eventSubscriber = val;
        }
    });
    Object.defineProperty(proxy, 'dispose', {
        configurable: false,
        value: () => context === null || context === void 0 ? void 0 : context.dispose()
    });
    Object.defineProperty(proxy, 'downloadResourceToCache', {
        configurable: false,
        value: (threadId, messageId, resourceUrl) => context === null || context === void 0 ? void 0 : context.downloadResourceToCache(threadId, messageId, resourceUrl)
    });
    Object.defineProperty(proxy, 'removeResourceFromCache', {
        configurable: false,
        value: (threadId, messageId, resourceUrl) => context === null || context === void 0 ? void 0 : context.removeResourceFromCache(threadId, messageId, resourceUrl)
    });
    Object.defineProperty(proxy, 'getState', {
        configurable: false,
        value: () => context === null || context === void 0 ? void 0 : context.getState()
    });
    Object.defineProperty(proxy, 'onStateChange', {
        configurable: false,
        value: (handler) => context === null || context === void 0 ? void 0 : context.onStateChange(handler)
    });
    Object.defineProperty(proxy, 'offStateChange', {
        configurable: false,
        value: (handler) => context === null || context === void 0 ? void 0 : context.offStateChange(handler)
    });
    return proxy;
};
//# sourceMappingURL=StatefulChatClient.js.map