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 BaseSessionHandler from './base-session-handler';
import { SessionTypes, SdkErrorTypes } from '../types/enums';
import { createAndEmitSdkError, isLiveScreenMonitorJid } from '../utils';
import { createNewStreamWithTrack } from '../media/media-utils';
export class LiveMonitoringSessionHandler extends BaseSessionHandler {
    constructor() {
        super(...arguments);
        this.sessionType = SessionTypes.liveScreenMonitoring;
        this._liveMonitoringObserver = false;
    }
    shouldHandleSessionByJid(jid) {
        return isLiveScreenMonitorJid(jid);
    }
    handleConversationUpdate() {
        /* no-op */
        return;
    }
    handlePropose(pendingSession) {
        const _super = Object.create(null, {
            handlePropose: { get: () => super.handlePropose }
        });
        return __awaiter(this, void 0, void 0, function* () {
            var _a;
            if (this.sdk._config.autoAcceptPendingLiveScreenMonitoringRequests) {
                return this.proceedWithSession(pendingSession);
            }
            // Auto-accept if current user is the target (fromUserId matches current user)
            if (pendingSession.fromUserId === ((_a = this.sdk._personDetails) === null || _a === void 0 ? void 0 : _a.id)) {
                this._liveMonitoringObserver = false;
                return this.proceedWithSession(pendingSession);
            }
            // if not auto accepting sessions, emit this event for the consumer to accept
            yield _super.handlePropose.call(this, pendingSession);
        });
    }
    acceptSession(session, params) {
        const _super = Object.create(null, {
            acceptSession: { get: () => super.acceptSession }
        });
        return __awaiter(this, void 0, void 0, function* () {
            // Store the liveMonitoringObserver flag (use existing flag if already set in handlePropose)
            this._liveMonitoringObserver = this._liveMonitoringObserver || params.liveMonitoringObserver || false;
            if (this._liveMonitoringObserver) {
                yield this.acceptSessionForObserver(session, params);
            }
            else {
                yield this.acceptSessionForTarget(session, params);
            }
            yield _super.acceptSession.call(this, session, params);
        });
    }
    acceptSessionForTarget(session, params) {
        return __awaiter(this, void 0, void 0, function* () {
            if (!params.mediaStream) {
                throw createAndEmitSdkError.call(this.sdk, SdkErrorTypes.session, `Cannot accept live screen monitoring session without providing a media stream`, { conversationId: session.conversationId, sessionType: this.sessionType });
            }
            // Set outbound stream to primary video media stream for monitoring targets
            session._outboundStream = params.mediaStream;
            let addMediaPromise = Promise.resolve();
            params.mediaStream.getTracks().forEach((track) => {
                addMediaPromise = addMediaPromise.then(() => {
                    const trackStream = createNewStreamWithTrack(track);
                    this.sdk.logger.info('Adding screen track to live screen monitoring session', { streamId: trackStream.id, trackId: track.id, label: track.label, conversationId: session.conversationId, sessionType: this.sessionType });
                    return session.pc.addTrack(track, trackStream);
                });
            });
            yield addMediaPromise;
            // Set unused video transceivers direction: inactive to not get sent to the observer clients
            const unusedTransceivers = session.pc.getTransceivers()
                .filter(transceiver => { var _a; return ((_a = transceiver.receiver.track) === null || _a === void 0 ? void 0 : _a.kind) === 'video' && !transceiver.sender.track; });
            this.sdk.logger.info(`Setting ${unusedTransceivers.length} unused video transceivers to inactive`, { conversationId: session.conversationId, sessionId: session.id });
            unusedTransceivers.forEach(transceiver => {
                transceiver.direction = "inactive";
            });
        });
    }
    acceptSessionForObserver(session, params) {
        return __awaiter(this, void 0, void 0, function* () {
            var _a;
            const videoElements = params.videoElements || (params.videoElement ? [params.videoElement] : [this.sdk._config.defaults.videoElement].filter(Boolean));
            const sessionInfo = { conversationId: session.conversationId, sessionId: session.id };
            if (!videoElements.length) {
                throw createAndEmitSdkError.call(this.sdk, SdkErrorTypes.invalid_options, 'acceptSession for live monitoring observer requires videoElements array or videoElement to be provided or in the default config', sessionInfo);
            }
            const tracks = session.pc.getReceivers()
                .filter(receiver => receiver.track)
                .map(receiver => receiver.track)
                .filter(track => track.kind === 'video');
            this.log('info', `Accepting live screen monitoring session as observer with ${videoElements.length} available video elements for ${session.pc.getReceivers().length} receivers with ${tracks.length} video tracks`);
            try {
                let addEmptyMediaPromise = Promise.resolve();
                tracks.forEach((_targetTrack) => {
                    addEmptyMediaPromise = addEmptyMediaPromise.then(() => {
                        const canvas = document.createElement('canvas');
                        canvas.width = 1;
                        canvas.height = 1;
                        const emptyStream = canvas.captureStream(0);
                        const emptyVideoTrack = emptyStream.getVideoTracks()[0];
                        this.sdk.logger.info('Adding empty screen track to live screen monitoring session', { streamId: emptyStream.id, trackId: emptyVideoTrack.id, label: emptyVideoTrack.label, conversationId: session.conversationId, sessionType: this.sessionType });
                        return session.pc.addTrack(emptyVideoTrack, emptyStream);
                    });
                });
                yield addEmptyMediaPromise;
            }
            catch (error) {
                this.sdk.logger.error('Error when adding empty video streams', error);
            }
            let videoElementIndex = 0;
            for (const track of tracks) {
                if (videoElementIndex < videoElements.length) {
                    const stream = createNewStreamWithTrack(track);
                    const videoElement = videoElements[videoElementIndex];
                    videoElement.muted = true;
                    videoElement.autoplay = true;
                    videoElement.srcObject = stream;
                    this.log('info', `Attached stream to video element at index ${videoElementIndex}`, Object.assign({ streamId: (_a = videoElement.srcObject) === null || _a === void 0 ? void 0 : _a.id, track: track }, sessionInfo));
                    videoElementIndex++;
                }
                session.emit('incomingMedia');
            }
        });
    }
    endSession(conversationId, session, reason) {
        const _super = Object.create(null, {
            endSession: { get: () => super.endSession }
        });
        return __awaiter(this, void 0, void 0, function* () {
            // Prevent the live monitor target from ending the session
            if (!this._liveMonitoringObserver) {
                throw createAndEmitSdkError.call(this.sdk, SdkErrorTypes.not_supported, `Live monitoring target cannot end the session`, { conversationId });
            }
            // Allow observers to end their participation
            this._liveMonitoringObserver = false;
            return _super.endSession.call(this, conversationId, session, reason);
        });
    }
    updateOutgoingMedia(session, _options) {
        this.log('warn', 'Cannot update outgoing media for live monitoring sessions', { sessionId: session.id, sessionType: session.sessionType });
        throw createAndEmitSdkError.call(this.sdk, SdkErrorTypes.not_supported, 'Cannot update outgoing media for live monitoring sessions');
    }
}
export default LiveMonitoringSessionHandler;
//# sourceMappingURL=live-monitoring-session-handler.js.map