"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.PubSubClient = void 0;
var tslib_1 = require("tslib");
var shared_utils_1 = require("@d-fischer/shared-utils");
var twitch_auth_1 = require("twitch-auth");
var twitch_common_1 = require("twitch-common");
var BasicPubSubClient_1 = require("./BasicPubSubClient");
var SingleUserPubSubClient_1 = require("./SingleUserPubSubClient");
/**
 * A high level PubSub client attachable to a multiple users.
 */
var PubSubClient = /** @class */ (function () {
    /**
     * Creates a new PubSub client.
     *
     * @param rootClient A previously existing PubSubClient instance.
     *
     * If not given, one will be created with the default options.
     */
    function PubSubClient(rootClient) {
        this._userClients = new Map();
        this._rootClient = rootClient !== null && rootClient !== void 0 ? rootClient : new BasicPubSubClient_1.BasicPubSubClient();
    }
    PubSubClient_1 = PubSubClient;
    /**
     * Attaches a new user to the listener and returns the user ID for convenience.
     *
     * @param apiClient The client that provides authentication for the user.
     * @param user The user that the client will be attached to.
     *
     * This should only be passed manually if you fetched the token info for the `apiClient` before.
     *
     * If not given, the user will be determined from the `apiClient`.
     */
    PubSubClient.prototype.registerUserListener = function (apiClient, user) {
        return tslib_1.__awaiter(this, void 0, void 0, function () {
            var userId;
            return tslib_1.__generator(this, function (_a) {
                switch (_a.label) {
                    case 0: return [4 /*yield*/, PubSubClient_1._getCorrectUserId(apiClient, user)];
                    case 1:
                        userId = _a.sent();
                        this._userClients.set(userId, new SingleUserPubSubClient_1.SingleUserPubSubClient({ twitchClient: apiClient, pubSubClient: this._rootClient }));
                        return [2 /*return*/, userId];
                }
            });
        });
    };
    /** @private */
    PubSubClient.prototype.getUserListener = function (user) {
        var userId = twitch_common_1.extractUserId(user);
        if (!this._userClients.has(userId)) {
            throw new Error("No API client registered for user ID " + userId + "\nRegister one using:\n\n\tpubSubClient.registerUserListener(apiClient);");
        }
        return this._userClients.get(userId);
    };
    /**
     * Adds a listener to bits events to the client.
     *
     * @param user The user the event will be subscribed for.
     * @param callback A function to be called when a bits event happens in the user's channel.
     *
     * It receives a {@PubSubBitsMessage} object.
     */
    PubSubClient.prototype.onBits = function (user, callback) {
        return tslib_1.__awaiter(this, void 0, void 0, function () {
            return tslib_1.__generator(this, function (_a) {
                return [2 /*return*/, this.getUserListener(user).onBits(callback)];
            });
        });
    };
    /**
     * Adds a listener to bits badge unlock events to the client.
     *
     * @param user The user the event will be subscribed for.
     * @param callback A function to be called when a bit badge is unlocked in the user's channel.
     *
     * It receives a {@PubSubBitsBadgeUnlockMessage} object.
     */
    PubSubClient.prototype.onBitsBadgeUnlock = function (user, callback) {
        return tslib_1.__awaiter(this, void 0, void 0, function () {
            return tslib_1.__generator(this, function (_a) {
                return [2 /*return*/, this.getUserListener(user).onBitsBadgeUnlock(callback)];
            });
        });
    };
    /**
     * Adds a listener to redemption events to the client.
     *
     * @param user The user the event will be subscribed for.
     * @param callback A function to be called when a channel point reward is redeemed in the user's channel.
     *
     * It receives a {@PubSubRedemptionMessage} object.
     */
    PubSubClient.prototype.onRedemption = function (user, callback) {
        return tslib_1.__awaiter(this, void 0, void 0, function () {
            return tslib_1.__generator(this, function (_a) {
                return [2 /*return*/, this.getUserListener(user).onRedemption(callback)];
            });
        });
    };
    /**
     * Adds a listener to subscription events to the client.
     *
     * @param user The user the event will be subscribed for.
     * @param callback A function to be called when a subscription event happens in the user's channel.
     *
     * It receives a {@PubSubSubscriptionMessage} object.
     */
    PubSubClient.prototype.onSubscription = function (user, callback) {
        return tslib_1.__awaiter(this, void 0, void 0, function () {
            return tslib_1.__generator(this, function (_a) {
                return [2 /*return*/, this.getUserListener(user).onSubscription(callback)];
            });
        });
    };
    /**
     * Adds a listener to whisper events to the client.
     *
     * @param user The user the event will be subscribed for.
     * @param callback A function to be called when a whisper is sent to the user.
     *
     * It receives a {@PubSubWhisperMessage} object.
     */
    PubSubClient.prototype.onWhisper = function (user, callback) {
        return tslib_1.__awaiter(this, void 0, void 0, function () {
            return tslib_1.__generator(this, function (_a) {
                return [2 /*return*/, this.getUserListener(user).onWhisper(callback)];
            });
        });
    };
    /**
     * Adds a listener to mod action events to the client.
     *
     * @param user The user the event will be subscribed for.
     * @param channel The channel the event will be subscribed for.
     * @param callback A function to be called when a mod action event is sent to the user.
     *
     * It receives a {@PubSubChatModActionMessage} object.
     */
    PubSubClient.prototype.onModAction = function (user, channel, callback) {
        return tslib_1.__awaiter(this, void 0, void 0, function () {
            return tslib_1.__generator(this, function (_a) {
                return [2 /*return*/, this.getUserListener(user).onModAction(channel, callback)];
            });
        });
    };
    PubSubClient._getCorrectUserId = function (apiClient, user) {
        return tslib_1.__awaiter(this, void 0, void 0, function () {
            var tokenInfo;
            return tslib_1.__generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        if (!user) return [3 /*break*/, 1];
                        return [2 /*return*/, twitch_common_1.extractUserId(user)];
                    case 1:
                        if (apiClient.tokenType === 'app') {
                            throw new twitch_auth_1.InvalidTokenTypeError('App tokens are not supported by PubSubClient; you need to pass authentication representing a user.');
                        }
                        return [4 /*yield*/, twitch_auth_1.getValidTokenFromProvider(apiClient)];
                    case 2:
                        tokenInfo = (_a.sent()).tokenInfo;
                        return [2 /*return*/, tokenInfo.userId];
                }
            });
        });
    };
    var PubSubClient_1;
    tslib_1.__decorate([
        shared_utils_1.Enumerable(false)
    ], PubSubClient.prototype, "_rootClient", void 0);
    tslib_1.__decorate([
        shared_utils_1.Enumerable(false)
    ], PubSubClient.prototype, "_userClients", void 0);
    PubSubClient = PubSubClient_1 = tslib_1.__decorate([
        twitch_common_1.rtfm('twitch-pubsub-client', 'PubSubClient')
    ], PubSubClient);
    return PubSubClient;
}());
exports.PubSubClient = PubSubClient;
