// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
import { getAssignedBreakoutRoom, getDeviceManager, getDiagnostics, getLatestErrors, getEnvironmentInfo, getCallState } from './baseSelectors';
import { getLatestNotifications } from './baseSelectors';
import { getMeetingConferencePhones } from './baseSelectors';
import { createSelector } from 'reselect';
import { DiagnosticQuality } from '@azure/communication-calling';
/**
 * Select the active errors from the state for the `Notification` component.
 *
 * Invariants:
 *   - `ErrorType` is never repeated in the returned errors.
 *   - Errors are returned in a fixed order by `ErrorType`.
 *
 * @public
 */
export const notificationStackSelector = createSelector([getLatestErrors, getLatestNotifications, getDiagnostics, getDeviceManager, getCallState, getEnvironmentInfo, getMeetingConferencePhones, getAssignedBreakoutRoom], (latestErrors, latestNotifications, diagnostics, deviceManager, callStatus, environmentInfo, meetingConference, assignedBreakoutRoom) => {
    var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u;
    // The order in which the errors are returned is significant: The `Notification` shows errors on the UI in that order.
    // There are several options for the ordering:
    //   - Sorted by when the errors happened (latest first / oldest first).
    //   - Stable sort by error type.
    //
    // We chose to stable sort by error type: We intend to show only a small number of errors on the UI and we do not
    // have timestamps for errors.
    const activeErrorMessages = [];
    const isSafari = () => {
        return (environmentInfo === null || environmentInfo === void 0 ? void 0 : environmentInfo.environment.browser) === 'safari';
    };
    const isMacOS = () => {
        return (environmentInfo === null || environmentInfo === void 0 ? void 0 : environmentInfo.environment.platform) === 'mac';
    };
    // Errors reported via diagnostics are more reliable than from API method failures, so process those first.
    let isTeamsMeetingWithPhones = false;
    if (meetingConference && meetingConference.length > 0) {
        isTeamsMeetingWithPhones = true;
    }
    if (((_a = diagnostics === null || diagnostics === void 0 ? void 0 : diagnostics.network.latest.networkReceiveQuality) === null || _a === void 0 ? void 0 : _a.value) === DiagnosticQuality.Bad || ((_b = diagnostics === null || diagnostics === void 0 ? void 0 : diagnostics.network.latest.networkReceiveQuality) === null || _b === void 0 ? void 0 : _b.value) === DiagnosticQuality.Poor) {
        if (isTeamsMeetingWithPhones) {
            activeErrorMessages.push({
                type: 'teamsMeetingCallNetworkQualityLow'
            });
        }
        else {
            activeErrorMessages.push({
                type: 'callNetworkQualityLow'
            });
        }
    }
    if (((_c = diagnostics === null || diagnostics === void 0 ? void 0 : diagnostics.media.latest.noSpeakerDevicesEnumerated) === null || _c === void 0 ? void 0 : _c.value) === true) {
        activeErrorMessages.push({
            type: 'callNoSpeakerFound'
        });
    }
    if (((_d = diagnostics === null || diagnostics === void 0 ? void 0 : diagnostics.media.latest.noMicrophoneDevicesEnumerated) === null || _d === void 0 ? void 0 : _d.value) === true) {
        activeErrorMessages.push({
            type: 'callNoMicrophoneFound'
        });
    }
    if (((_e = deviceManager.deviceAccess) === null || _e === void 0 ? void 0 : _e.audio) === false && isSafari()) {
        activeErrorMessages.push({
            type: 'callMicrophoneAccessDeniedSafari'
        });
    }
    if (((_f = diagnostics === null || diagnostics === void 0 ? void 0 : diagnostics.media.latest.microphonePermissionDenied) === null || _f === void 0 ? void 0 : _f.value) === true && isMacOS()) {
        activeErrorMessages.push({
            type: 'callMacOsMicrophoneAccessDenied'
        });
    }
    else if (((_g = deviceManager.deviceAccess) === null || _g === void 0 ? void 0 : _g.audio) === false && !isSafari() || ((_h = diagnostics === null || diagnostics === void 0 ? void 0 : diagnostics.media.latest.microphonePermissionDenied) === null || _h === void 0 ? void 0 : _h.value) === true && !isMacOS()) {
        activeErrorMessages.push({
            type: 'callMicrophoneAccessDenied'
        });
    }
    const microphoneMuteUnexpectedlyDiagnostic = (diagnostics === null || diagnostics === void 0 ? void 0 : diagnostics.media.latest.microphoneMuteUnexpectedly) || (diagnostics === null || diagnostics === void 0 ? void 0 : diagnostics.media.latest.microphoneNotFunctioning);
    if (microphoneMuteUnexpectedlyDiagnostic) {
        if (microphoneMuteUnexpectedlyDiagnostic.value === DiagnosticQuality.Bad) {
            // Inform the user that microphone stopped working and inform them to start microphone again
            activeErrorMessages.push({
                type: 'callMicrophoneMutedBySystem'
            });
        }
        else if (microphoneMuteUnexpectedlyDiagnostic.value === DiagnosticQuality.Good) {
            // Inform the user that microphone recovered
            activeErrorMessages.push({
                type: 'callMicrophoneUnmutedBySystem'
            });
        }
    }
    const cameraStoppedUnexpectedlyDiagnostic = diagnostics === null || diagnostics === void 0 ? void 0 : diagnostics.media.latest.cameraStoppedUnexpectedly;
    if (cameraStoppedUnexpectedlyDiagnostic) {
        if (cameraStoppedUnexpectedlyDiagnostic.value === DiagnosticQuality.Bad) {
            // Inform the user that camera stopped working and inform them to start video again
            activeErrorMessages.push({
                type: 'callVideoStoppedBySystem'
            });
        }
        else if (cameraStoppedUnexpectedlyDiagnostic.value === DiagnosticQuality.Good) {
            // Inform the user that camera recovered
            activeErrorMessages.push({
                type: 'callVideoRecoveredBySystem'
            });
        }
    }
    if (((_j = deviceManager.deviceAccess) === null || _j === void 0 ? void 0 : _j.video) === false && isSafari()) {
        activeErrorMessages.push({
            type: 'callCameraAccessDeniedSafari'
        });
    }
    else if (((_k = deviceManager.deviceAccess) === null || _k === void 0 ? void 0 : _k.video) === false) {
        activeErrorMessages.push({
            type: 'callCameraAccessDenied'
        });
    }
    else {
        if (((_l = diagnostics === null || diagnostics === void 0 ? void 0 : diagnostics.media.latest.cameraFreeze) === null || _l === void 0 ? void 0 : _l.value) === true) {
            activeErrorMessages.push({
                type: 'cameraFrozenForRemoteParticipants'
            });
        }
    }
    /**
     * show the Mac specific strings if the platform is detected as mac
     */
    if (((_m = diagnostics === null || diagnostics === void 0 ? void 0 : diagnostics.media.latest.cameraPermissionDenied) === null || _m === void 0 ? void 0 : _m.value) === true && isMacOS()) {
        activeErrorMessages.push({
            type: 'callMacOsCameraAccessDenied'
        });
    }
    /**
     * This UFD only works on mac still so we should only see it fire on mac.
     */
    if (((_o = diagnostics === null || diagnostics === void 0 ? void 0 : diagnostics.media.latest.screenshareRecordingDisabled) === null || _o === void 0 ? void 0 : _o.value) === true && isMacOS()) {
        activeErrorMessages.push({
            type: 'callMacOsScreenShareAccessDenied'
        });
    }
    else if (((_p = diagnostics === null || diagnostics === void 0 ? void 0 : diagnostics.media.latest.screenshareRecordingDisabled) === null || _p === void 0 ? void 0 : _p.value) === true) {
        activeErrorMessages.push({
            type: 'startScreenShareGeneric'
        });
    }
    // Prefer to show errors with privacy implications.
    appendActiveErrorIfDefined(activeErrorMessages, latestErrors, 'Call.stopVideo', 'stopVideoGeneric');
    appendActiveErrorIfDefined(activeErrorMessages, latestErrors, 'Call.mute', 'muteGeneric');
    appendActiveErrorIfDefined(activeErrorMessages, latestErrors, 'Call.stopScreenSharing', 'stopScreenShareGeneric');
    if (((_q = latestErrors['Call.startVideo']) === null || _q === void 0 ? void 0 : _q.message) === 'Call.startVideo: Video operation failure SourceUnavailableError') {
        appendActiveErrorIfDefined(activeErrorMessages, latestErrors, 'Call.startVideo', 'callCameraAlreadyInUse');
    }
    else if (((_r = latestErrors['Call.startVideo']) === null || _r === void 0 ? void 0 : _r.message) === 'Call.startVideo: Video operation failure permissionDeniedError') {
        appendActiveErrorIfDefined(activeErrorMessages, latestErrors, 'Call.startVideo', 'callCameraAccessDenied');
    }
    else {
        appendActiveErrorIfDefined(activeErrorMessages, latestErrors, 'Call.startVideo', 'startVideoGeneric');
    }
    appendActiveErrorIfDefined(activeErrorMessages, latestErrors, 'Call.unmute', 'unmuteGeneric');
    if (latestNotifications && !latestNotifications['capabilityUnmuteMicAbsent'] && !latestNotifications['capabilityUnmuteMicPresent']) {
        appendActiveErrorIfDefined(activeErrorMessages, latestErrors, 'Call.mutedByOthers', 'mutedByRemoteParticipant');
    }
    appendActiveErrorIfDefined(activeErrorMessages, latestErrors, 'VideoEffectsFeature.startEffects', 'unableToStartVideoEffect');
    if (((_s = latestErrors['CallAgent.join']) === null || _s === void 0 ? void 0 : _s.message) === 'CallAgent.join: Invalid meeting link') {
        appendActiveErrorIfDefined(activeErrorMessages, latestErrors, 'CallAgent.join', 'failedToJoinCallInvalidMeetingLink');
    }
    else {
        appendActiveErrorIfDefined(activeErrorMessages, latestErrors, 'CallAgent.join', 'failedToJoinCallGeneric');
    }
    if ((_t = latestErrors['Call.feature']) === null || _t === void 0 ? void 0 : _t.message.match(/Call\.feature: startSpotlight failed\. \d+ is the max number of participants that can be Spotlighted/g)) {
        appendActiveErrorIfDefined(activeErrorMessages, latestErrors, 'Call.feature', 'startSpotlightWhileMaxParticipantsAreSpotlighted');
    }
    //below is for active notifications
    const activeNotifications = [];
    if (((_u = diagnostics === null || diagnostics === void 0 ? void 0 : diagnostics.media.latest.speakingWhileMicrophoneIsMuted) === null || _u === void 0 ? void 0 : _u.value) &&
        // only show this notification when the participant is in an active call and not on screens such as Lobby
        callStatus === 'Connected') {
        activeNotifications.push({
            type: 'speakingWhileMuted',
            timestamp: new Date(Date.now()),
            autoDismiss: true,
            ariaLive: 'off' // "You're muted" is too noisy, so we don't want to announce it.
        });
    }
    if (latestNotifications['assignedBreakoutRoomOpened']) {
        activeNotifications.push({
            type: 'assignedBreakoutRoomOpened',
            timestamp: latestNotifications['assignedBreakoutRoomOpened'].timestamp
        });
    }
    if (latestNotifications['assignedBreakoutRoomOpenedPromptJoin'] && assignedBreakoutRoom) {
        activeNotifications.push({
            type: 'assignedBreakoutRoomOpenedPromptJoin',
            timestamp: latestNotifications['assignedBreakoutRoomOpenedPromptJoin'].timestamp,
            onClickPrimaryButton: () => assignedBreakoutRoom.join()
        });
    }
    if (latestNotifications['assignedBreakoutRoomChanged']) {
        activeNotifications.push({
            type: 'assignedBreakoutRoomChanged',
            timestamp: latestNotifications['assignedBreakoutRoomChanged'].timestamp
        });
    }
    if (latestNotifications['assignedBreakoutRoomClosed']) {
        activeNotifications.push({
            type: 'assignedBreakoutRoomClosed',
            timestamp: latestNotifications['assignedBreakoutRoomClosed'].timestamp
        });
    }
    if (latestNotifications['breakoutRoomJoined']) {
        activeNotifications.push({
            type: 'breakoutRoomJoined',
            timestamp: latestNotifications['breakoutRoomJoined'].timestamp
        });
    }
    if (latestNotifications['breakoutRoomClosingSoon']) {
        activeNotifications.push({
            type: 'breakoutRoomClosingSoon',
            timestamp: latestNotifications['breakoutRoomClosingSoon'].timestamp
        });
    }
    if (latestNotifications['capabilityTurnVideoOnPresent']) {
        activeNotifications.push({
            type: 'capabilityTurnVideoOnPresent',
            timestamp: latestNotifications['capabilityTurnVideoOnPresent'].timestamp
        });
    }
    if (latestNotifications['capabilityTurnVideoOnAbsent']) {
        activeNotifications.push({
            type: 'capabilityTurnVideoOnAbsent',
            timestamp: latestNotifications['capabilityTurnVideoOnAbsent'].timestamp
        });
    }
    if (latestNotifications['capabilityUnmuteMicPresent']) {
        activeNotifications.push({
            type: 'capabilityUnmuteMicPresent',
            timestamp: latestNotifications['capabilityUnmuteMicPresent'].timestamp
        });
    }
    if (latestNotifications['capabilityUnmuteMicAbsent']) {
        activeNotifications.push({
            type: 'capabilityUnmuteMicAbsent',
            timestamp: latestNotifications['capabilityUnmuteMicAbsent'].timestamp
        });
    }
    if (latestNotifications['togetherModeStarted']) {
        activeNotifications.push({
            type: 'togetherModeStarted',
            timestamp: latestNotifications['togetherModeStarted'].timestamp,
            autoDismiss: true
        });
    }
    if (latestNotifications['togetherModeEnded']) {
        activeNotifications.push({
            type: 'togetherModeEnded',
            timestamp: latestNotifications['togetherModeEnded'].timestamp,
            autoDismiss: true
        });
    }
    return {
        activeErrorMessages: activeErrorMessages,
        activeNotifications: activeNotifications
    };
});
const appendActiveErrorIfDefined = (activeErrorMessages, latestErrors, target, activeErrorType) => {
    if (latestErrors[target] === undefined) {
        return;
    }
    activeErrorMessages.push({
        type: activeErrorType,
        timestamp: latestErrors[target].timestamp
    });
};
//# sourceMappingURL=notificationStackSelector.js.map