"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.PushStream = void 0;
const tslib_1 = require("tslib");
const events_1 = require("events");
const socketClient_1 = require("./socketClient");
const constants_1 = require("../constants");
const pushStreamTypes_1 = require("./pushStreamTypes");
const DataModifier_1 = require("./DataModifier");
const helpers_1 = require("../helpers");
const chat_1 = require("../pushapi/chat");
const config_1 = require("../config");
class PushStream extends events_1.EventEmitter {
    constructor(account, _listen, options, decryptedPgpPvtKey, progressHook, signer) {
        var _a;
        super();
        this._listen = _listen;
        this.decryptedPgpPvtKey = decryptedPgpPvtKey;
        this.progressHook = progressHook;
        this.signer = signer;
        this.account = account;
        this.raw = (_a = options.raw) !== null && _a !== void 0 ? _a : false;
        this.options = options;
        this.listen = _listen;
        this.chatInstance = new chat_1.Chat(this.account, this.options.env, config_1.ALPHA_FEATURE_CONFIG[constants_1.PACKAGE_BUILD], this.decryptedPgpPvtKey, this.signer, this.progressHook);
    }
    static initialize(account, listen, env, decryptedPgpPvtKey, progressHook, signer, options) {
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            const defaultOptions = {
                raw: false,
                connection: {
                    auto: true,
                    retries: 3,
                },
                env: env,
            };
            if (!listen || listen.length === 0) {
                throw new Error('The listen property must have at least one STREAM type.');
            }
            const settings = Object.assign(Object.assign({}, defaultOptions), options);
            const accountToUse = settings.overrideAccount || account;
            const stream = new PushStream(accountToUse, listen, settings, decryptedPgpPvtKey, progressHook, signer);
            return stream;
        });
    }
    connect() {
        var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            const shouldInitializeChatSocket = !this.listen ||
                this.listen.length === 0 ||
                this.listen.includes(pushStreamTypes_1.STREAM.CHAT) ||
                this.listen.includes(pushStreamTypes_1.STREAM.CHAT_OPS);
            const shouldInitializeNotifSocket = !this.listen ||
                this.listen.length === 0 ||
                this.listen.includes(pushStreamTypes_1.STREAM.NOTIF) ||
                this.listen.includes(pushStreamTypes_1.STREAM.NOTIF_OPS);
            let isChatSocketConnected = false;
            let isNotifSocketConnected = false;
            // Function to check and emit the STREAM.CONNECT event
            const checkAndEmitConnectEvent = () => {
                if (((shouldInitializeChatSocket && isChatSocketConnected) ||
                    !shouldInitializeChatSocket) &&
                    ((shouldInitializeNotifSocket && isNotifSocketConnected) ||
                        !shouldInitializeNotifSocket)) {
                    this.emit(pushStreamTypes_1.STREAM.CONNECT);
                    console.log('Emitted STREAM.CONNECT');
                }
            };
            const handleSocketDisconnection = (socketType) => tslib_1.__awaiter(this, void 0, void 0, function* () {
                //console.log(`${socketType.toUpperCase()} Socket Disconnected`);
                if (socketType === 'chat') {
                    isChatSocketConnected = false;
                    if (isNotifSocketConnected) {
                        if (this.pushNotificationSocket &&
                            this.pushNotificationSocket.connected) {
                            //console.log('Disconnecting Notification Socket...');
                            this.pushNotificationSocket.disconnect();
                        }
                    }
                    else {
                        // Emit STREAM.DISCONNECT only if the notification socket was already disconnected
                        this.emit(pushStreamTypes_1.STREAM.DISCONNECT);
                        console.log('Emitted STREAM.DISCONNECT ');
                    }
                }
                else if (socketType === 'notif') {
                    isNotifSocketConnected = false;
                    if (isChatSocketConnected) {
                        if (this.pushChatSocket && this.pushChatSocket.connected) {
                            //console.log('Disconnecting Chat Socket...');
                            this.pushChatSocket.disconnect();
                        }
                    }
                    else {
                        // Emit STREAM.DISCONNECT only if the chat socket was already disconnected
                        this.emit(pushStreamTypes_1.STREAM.DISCONNECT);
                        console.log('Emitted STREAM.DISCONNECT');
                    }
                }
            });
            if (shouldInitializeChatSocket) {
                if (!this.pushChatSocket) {
                    // If pushChatSocket does not exist, create a new socket connection
                    this.pushChatSocket = (0, socketClient_1.createSocketConnection)({
                        user: (0, helpers_1.walletToPCAIP10)(this.account),
                        socketType: 'chat',
                        socketOptions: {
                            autoConnect: (_c = (_b = (_a = this.options) === null || _a === void 0 ? void 0 : _a.connection) === null || _b === void 0 ? void 0 : _b.auto) !== null && _c !== void 0 ? _c : true,
                            reconnectionAttempts: (_f = (_e = (_d = this.options) === null || _d === void 0 ? void 0 : _d.connection) === null || _e === void 0 ? void 0 : _e.retries) !== null && _f !== void 0 ? _f : 3,
                        },
                        env: (_g = this.options) === null || _g === void 0 ? void 0 : _g.env,
                    });
                    if (!this.pushChatSocket) {
                        throw new Error('Push chat socket not connected');
                    }
                }
                else if (!this.pushChatSocket.connected) {
                    // If pushChatSocket exists but is not connected, attempt to reconnect
                    console.log('Attempting to reconnect push chat socket...');
                    this.pushChatSocket.connect(); // Assuming connect() is the method to re-establish connection
                }
                else {
                    // If pushChatSocket is already connected
                    console.log('Push chat socket already connected');
                }
            }
            if (shouldInitializeNotifSocket) {
                if (!this.pushNotificationSocket) {
                    // If pushNotificationSocket does not exist, create a new socket connection
                    this.pushNotificationSocket = (0, socketClient_1.createSocketConnection)({
                        user: (0, helpers_1.pCAIP10ToWallet)(this.account),
                        env: (_h = this.options) === null || _h === void 0 ? void 0 : _h.env,
                        socketOptions: {
                            autoConnect: (_l = (_k = (_j = this.options) === null || _j === void 0 ? void 0 : _j.connection) === null || _k === void 0 ? void 0 : _k.auto) !== null && _l !== void 0 ? _l : true,
                            reconnectionAttempts: (_p = (_o = (_m = this.options) === null || _m === void 0 ? void 0 : _m.connection) === null || _o === void 0 ? void 0 : _o.retries) !== null && _p !== void 0 ? _p : 3,
                        },
                    });
                    if (!this.pushNotificationSocket) {
                        throw new Error('Push notification socket not connected');
                    }
                }
                else if (!this.pushNotificationSocket.connected) {
                    // If pushNotificationSocket exists but is not connected, attempt to reconnect
                    console.log('Attempting to reconnect push notification socket...');
                    this.pushNotificationSocket.connect(); // Assuming connect() is the method to re-establish connection
                }
                else {
                    // If pushNotificationSocket is already connected
                    console.log('Push notification socket already connected');
                }
            }
            const shouldEmit = (eventType) => {
                if (!this.listen || this.listen.length === 0) {
                    return true;
                }
                return this.listen.includes(eventType);
            };
            if (this.pushChatSocket) {
                this.pushChatSocket.on(pushStreamTypes_1.EVENTS.CONNECT, () => tslib_1.__awaiter(this, void 0, void 0, function* () {
                    isChatSocketConnected = true;
                    checkAndEmitConnectEvent();
                    console.log(`Chat Socket Connected (ID: ${this.pushChatSocket.id})`);
                }));
                this.pushChatSocket.on(pushStreamTypes_1.EVENTS.DISCONNECT, () => tslib_1.__awaiter(this, void 0, void 0, function* () {
                    yield handleSocketDisconnection('chat');
                    //console.log(`Chat Socket Disconnected`);
                }));
                this.pushChatSocket.on(pushStreamTypes_1.EVENTS.CHAT_GROUPS, (data) => {
                    try {
                        const modifiedData = DataModifier_1.DataModifier.handleChatGroupEvent(data, this.raw);
                        modifiedData.event = DataModifier_1.DataModifier.convertToProposedName(modifiedData.event);
                        DataModifier_1.DataModifier.handleToField(modifiedData);
                        if (this.shouldEmitChat(data.chatId)) {
                            if (data.eventType === pushStreamTypes_1.GroupEventType.JoinGroup ||
                                data.eventType === pushStreamTypes_1.GroupEventType.LeaveGroup ||
                                data.eventType === pushStreamTypes_1.MessageEventType.Request ||
                                data.eventType === pushStreamTypes_1.GroupEventType.Remove) {
                                if (shouldEmit(pushStreamTypes_1.STREAM.CHAT)) {
                                    this.emit(pushStreamTypes_1.STREAM.CHAT, modifiedData);
                                }
                            }
                            else {
                                if (shouldEmit(pushStreamTypes_1.STREAM.CHAT_OPS)) {
                                    this.emit(pushStreamTypes_1.STREAM.CHAT_OPS, modifiedData);
                                }
                            }
                        }
                    }
                    catch (error) {
                        console.error('Error handling CHAT_GROUPS event:', error, 'Data:', data);
                    }
                });
                this.pushChatSocket.on(pushStreamTypes_1.EVENTS.CHAT_RECEIVED_MESSAGE, (data) => tslib_1.__awaiter(this, void 0, void 0, function* () {
                    try {
                        if (data.messageCategory == 'Chat' ||
                            data.messageCategory == 'Request') {
                            // Dont call this if read only mode ?
                            if (this.signer) {
                                data = yield this.chatInstance.decrypt([data]);
                                data = data[0];
                            }
                        }
                        const modifiedData = DataModifier_1.DataModifier.handleChatEvent(data, this.raw);
                        modifiedData.event = DataModifier_1.DataModifier.convertToProposedName(modifiedData.event);
                        DataModifier_1.DataModifier.handleToField(modifiedData);
                        if (this.shouldEmitChat(data.chatId)) {
                            if (shouldEmit(pushStreamTypes_1.STREAM.CHAT)) {
                                this.emit(pushStreamTypes_1.STREAM.CHAT, modifiedData);
                            }
                        }
                    }
                    catch (error) {
                        console.error('Error handling CHAT_RECEIVED_MESSAGE event:', error, 'Data:', data);
                    }
                }));
            }
            if (this.pushNotificationSocket) {
                this.pushNotificationSocket.on(pushStreamTypes_1.EVENTS.CONNECT, () => tslib_1.__awaiter(this, void 0, void 0, function* () {
                    console.log(`Notification Socket Connected (ID: ${this.pushNotificationSocket.id})`);
                    isNotifSocketConnected = true;
                    checkAndEmitConnectEvent();
                }));
                this.pushNotificationSocket.on(pushStreamTypes_1.EVENTS.DISCONNECT, () => tslib_1.__awaiter(this, void 0, void 0, function* () {
                    yield handleSocketDisconnection('notif');
                    //console.log(`Notification Socket Disconnected`);
                }));
                this.pushNotificationSocket.on(pushStreamTypes_1.EVENTS.USER_FEEDS, (data) => {
                    try {
                        const modifiedData = DataModifier_1.DataModifier.mapToNotificationEvent(data, pushStreamTypes_1.NotificationEventType.INBOX, this.account === data.sender ? 'self' : 'other', this.raw);
                        if (this.shouldEmitChannel(modifiedData.from)) {
                            if (shouldEmit(pushStreamTypes_1.STREAM.NOTIF)) {
                                this.emit(pushStreamTypes_1.STREAM.NOTIF, modifiedData);
                            }
                        }
                    }
                    catch (error) {
                        console.error('Error handling USER_FEEDS event:', error, 'Data:', data);
                    }
                });
                this.pushNotificationSocket.on(pushStreamTypes_1.EVENTS.USER_SPAM_FEEDS, (data) => {
                    try {
                        const modifiedData = DataModifier_1.DataModifier.mapToNotificationEvent(data, pushStreamTypes_1.NotificationEventType.SPAM, this.account === data.sender ? 'self' : 'other', this.raw);
                        modifiedData.origin =
                            this.account === modifiedData.from ? 'self' : 'other';
                        if (this.shouldEmitChannel(modifiedData.from)) {
                            if (shouldEmit(pushStreamTypes_1.STREAM.NOTIF)) {
                                this.emit(pushStreamTypes_1.STREAM.NOTIF, modifiedData);
                            }
                        }
                    }
                    catch (error) {
                        console.error('Error handling USER_SPAM_FEEDS event:', error, 'Data:', data);
                    }
                });
            }
        });
    }
    disconnect() {
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            // Disconnect push chat socket if connected
            if (this.pushChatSocket) {
                this.pushChatSocket.disconnect();
                //console.log('Push chat socket disconnected.');
            }
            // Disconnect push notification socket if connected
            if (this.pushNotificationSocket) {
                this.pushNotificationSocket.disconnect();
                //console.log('Push notification socket disconnected.');
            }
        });
    }
    shouldEmitChat(dataChatId) {
        var _a;
        if (!((_a = this.options.filter) === null || _a === void 0 ? void 0 : _a.chats) ||
            this.options.filter.chats.length === 0 ||
            this.options.filter.chats.includes('*')) {
            return true;
        }
        return this.options.filter.chats.includes(dataChatId);
    }
    shouldEmitChannel(dataChannelId) {
        var _a;
        if (!((_a = this.options.filter) === null || _a === void 0 ? void 0 : _a.channels) ||
            this.options.filter.channels.length === 0 ||
            this.options.filter.channels.includes('*')) {
            return true;
        }
        return this.options.filter.channels.includes(dataChannelId);
    }
}
exports.PushStream = PushStream;
//# sourceMappingURL=PushStream.js.map