import { createSelector as e } from "@reduxjs/toolkit"
import {
CALL_STATUS as t,
STREAM_TYPE as r,
CALL_STATE_KEY as n,
CALL_SETTINGS_STATE_KEY as a,
} from "./call.constants"
import {
CALL_SETTINGS_INITIAL_STATE as l,
callSettingsReducer as s,
getMyScreenStreamId as o,
} from "./call-settings.reducer"
import {
setCallIds as c,
setCallStatus as m,
showCallConfirmLeave as d,
showCallAutoEndPopup as p,
updateCallAutoEndCountdown as C,
setCallShareScreenDialogOpened as i,
openCallSettings as g,
setCallRemoteMediaAudioError as u,
removeCallRemoteMediaAudioError as I,
updateCallRemoteMedia as S,
removeCallRemoteMedia as y,
increaseCallPeersCount as w,
decreaseCallPeersCount as b,
removeCallPeersCount as x,
setCallPeers as M,
callSetIncomingDMCall as P,
callResetIncomingDMCall as B,
setDmCallsV2Enabled as f,
setActiveCalls as E,
setPendingCall as A,
} from "./call.action"
import {
addCallMemberId as h,
removeCallMemberId as v,
addCallMemberStream as N,
removeCallMemberStream as k,
addCallUnknownPresenceEvt as T,
} from "./call-presence.action"
import {
callCancel as O,
callJoinCmd as D,
callJoinedEvt as L,
callLeave as G,
callReset as R,
} from "./call-status.action"
import {
addCallMemberIdReducer as U,
addCallMemberStreamReducer as V,
addCallUnknownPresenceEvtReducer as J,
removeCallMemberIdReducer as j,
removeCallMemberStreamReducer as _,
removeCallRemoteMediaReducer as H,
updateCallRemoteMediaReducer as z,
} from "./call-presence.reducer"
import { getNextPositionPreservedList as K, mergeActivePresences as Y } from "./utils"
import { getMembersByRoomIdState as q } from "../member"
import { getRoomCallsV2Supported as F } from "../room/room.feature"
import { getNetworkPeers as Q } from "../network/network.reducer"
import { EMPTY_ARRAY as W } from "../lib/array"
export const INITIAL_STATE = {
callId: "",
memberId: "",
swarmId: "",
settings: l,
presencesSortedByActivity: [],
presenceMemberIds: [],
presenceMemberSwarmIds: [],
presenceBySwarmId: {},
presenceSwarmByMemberId: {},
unknownMemberPresence: {},
activeCalls: null,
activeCallMemberIds: null,
mediaBySwarmId: {},
connectedMemberIds: {},
peersCounter: {},
showConfirmLeave: !1,
showAutoEndPopup: !1,
autoEndCountdown: 1 / 0,
shareScreenDialogOpened: !1,
status: t.DISABLED,
incomingCall: null,
pendingCall: null,
dmCallsV2Enabled: !1,
}
export const callReducer = (e = INITIAL_STATE, r) => {
const { type: n, payload: l } = r
switch (n) {
case c.type: {
const { callId: t, memberId: r } = l
return { ...e, callId: t, memberId: r }
}
case m.type:
return l === t.DISABLED
? { ...INITIAL_STATE, peersCounter: e.peersCounter }
: e.status === t.SETTINGS
? e
: { ...e, status: l }
case d.type:
return { ...e, showConfirmLeave: !!l }
case p.type:
return { ...e, showAutoEndPopup: !!l }
case C.type:
return { ...e, autoEndCountdown: l }
case i.type:
return { ...e, shareScreenDialogOpened: !!l }
case g.type:
return { ...e, status: t.SETTINGS }
case u.type: {
const { swarmId: t, error: r } = l,
n = e.mediaBySwarmId[t]
return n && r
? { ...e, mediaBySwarmId: { ...e.mediaBySwarmId, [t]: { ...n, audioError: r } } }
: e
}
case I.type: {
const { swarmId: t } = l,
r = e.mediaBySwarmId[t]
if (r && r.audioError) {
const n = { ...r }
return (delete n.audioError, { ...e, mediaBySwarmId: { ...e.mediaBySwarmId, [t]: n } })
}
return e
}
case S.type:
return z(e, r)
case y.type:
return H(e, r)
case w.type: {
const { roomId: t, swarmId: r } = l,
n = e.peersCounter[t] || []
return n.indexOf(r) < 0 ? { ...e, peersCounter: { ...e.peersCounter, [t]: [...n, r] } } : e
}
case b.type: {
const { roomId: t, swarmId: r } = l
return {
...e,
peersCounter: { ...e.peersCounter, [t]: (e.peersCounter[t] || []).filter((e) => e !== r) },
}
}
case x.type: {
const { roomId: t } = l,
r = { ...e.peersCounter }
return (delete r[t], { ...e, peersCounter: r })
}
case M.type: {
const { roomId: t, ids: r } = l
return { ...e, peersCounter: { ...e.peersCounter, [t]: r } }
}
case E.type:
return { ...e, activeCalls: l.calls, activeCallMemberIds: l.memberIds }
case h.type:
return U(e, r)
case v.type:
return j(e, r)
case N.type:
return V(e, r)
case k.type:
return _(e, r)
case T.type:
return J(e, r)
case D.type:
return { ...e, status: t.JOINING }
case L.type:
return { ...e, status: t.JOINED }
case R.type:
return {
...INITIAL_STATE,
peersCounter: e.peersCounter,
incomingCall: e.incomingCall,
pendingCall: e.pendingCall,
dmCallsV2Enabled: e.dmCallsV2Enabled,
}
case O.type:
case G.type:
return {
...e,
showConfirmLeave: !1,
status: t.READY,
mediaBySwarmId: {},
connectedMemberIds: {},
activeCalls: null,
activeCallMemberIds: null,
pendingCall: null,
}
case P.type:
return { ...e, incomingCall: l }
case B.type:
return { ...e, incomingCall: null }
case A.type:
return { ...e, pendingCall: l }
case f.type:
return { ...e, dmCallsV2Enabled: !!l }
default: {
const t = s(e[a], r)
return e[a] === t ? e : { ...e, [a]: t }
}
}
}
export const isCallReady = (e) => e !== t.DISABLED && e !== t.LOADING
export const isCallSettingsMode = (e) => e === t.SETTINGS
export const isCallJoinedMode = (e) => e === t.JOINING || e === t.JOINED
export const getCallState = (e) => e[n]
export const getCallId = (e) => e[n].callId
export const getCallMyMemberId = (e) => e[n].memberId
export const getCallStatus = (e) => e[n].status
export const getCallShowConfirmLeave = (e) => getCallState(e).showConfirmLeave
export const getCallShowAutoEndPopup = (e) => getCallState(e).showAutoEndPopup
export const getCallAutoEndCountdown = (e) => getCallState(e).autoEndCountdown
export const getCallShareScreenDialogOpened = (e) => getCallState(e).shareScreenDialogOpened
export const getCallPresenceState = (e) => getCallState(e).presenceBySwarmId
export const getCallMediaState = (e) => getCallState(e).mediaBySwarmId
export const getCallPeerVideoCount = (e) =>
Object.values(getCallState(e).mediaBySwarmId).filter(
(e) => !!e?.streamByName?.[r.CAMERA] && !1 === e.isVideoMuted,
).length
export const getCallKnownMemberCount = (e) => getCallState(e).presenceMemberIds.length
export const getCallPresenceMemberSwarmIds = (e) => getCallState(e).presenceMemberSwarmIds
export const getCallUnknownPresenceState = (e) => getCallState(e).unknownMemberPresence
export const getActiveCalls = (e) => getCallState(e).activeCalls
export const getActiveCallMemberIds = (e) => getCallState(e).activeCallMemberIds
export const getIsActiveCallMember = (e) => (t) => {
const r = getActiveCallMemberIds(t)
return null !== r && r.includes(e)
}
export const makeGetIsActiveCallMember = (t) =>
e([getActiveCallMemberIds], (e) => null !== e && e.includes(t))
export const getCallTopSortedPresences = (e) => getCallState(e).presencesSortedByActivity
export const getCallUnknownPresenceIds = e(getCallUnknownPresenceState, (e) => Object.keys(e))
export const getCallIncomingCall = (e) => getCallState(e).incomingCall
export const getCallIncomingDMRoomId = (e) => getCallIncomingCall(e)?.roomId ?? null
export const getPendingCall = (e) => getCallState(e).pendingCall
export const getDmCallsV2Enabled = (e) => getCallState(e).dmCallsV2Enabled
export const getIsCallsV2Supported = (e) => (t) => F(e)(t)
export const getCallPresenceIds = e(
[getActiveCallMemberIds, getCallPresenceMemberSwarmIds, getCallUnknownPresenceIds],
(e, t, r) => (null !== e ? e : 0 === r.length ? t : [...t, ...r]),
)
export const getCallPresenceCount = (e) => getCallPresenceIds(e).length
export const getIsPresenceUnknown = (e) => (t) => -1 !== getCallUnknownPresenceIds(t)?.indexOf(e)
export const makeGetIsPresenceUnknown = (t) =>
e([getCallUnknownPresenceIds], (e) => -1 !== e?.indexOf(t))
export const getCallPresenceSwarmByMemberIds = (e) => getCallState(e).presenceSwarmByMemberId
export const getCallRemoteMediaById = (e) => (t) => {
const { mediaBySwarmId: r } = getCallState(t)
if (r[e]) return r[e]
const n = getCallPresenceSwarmByMemberIds(t)[e]
return n ? r[n] : void 0
}
export const getCallPresenceById = (e) => (t) => {
const { presenceBySwarmId: r } = getCallState(t)
if (r[e]) return r[e]
const n = getCallPresenceSwarmByMemberIds(t)[e]
return n ? r[n] : void 0
}
export const getCallIsOngoing = e(
getCallState,
getCallUnknownPresenceIds,
({ status: e, presenceMemberIds: t, activeCallMemberIds: r }, n) =>
isCallJoinedMode(e) || t.length + n.length > 0 || (null !== r && r.length > 0),
)
export const getCallPeersCount = (e, t) => getCallState(e).peersCounter?.[t]?.length || 0
export const getCallPeerSwarmIds = (e) => (t) => getCallState(t).peersCounter?.[e] || W
export const makeCallMemberIdsByRoomId = (t, r) => {
const n = new Map()
let a = []
return e(getCallPeerSwarmIds(t), q(t), (e, { bySwarmId: t, byMemberId: l }) => {
n.clear()
for (let a = 0; a < e.length && n.size < r; a += 1) {
const r = t[e[a]]?.memberId
r ? n.set(r, !0) : l[e[a]] && n.set(e[a], !0)
}
return ((n.size !== a.length || a.some((e) => !n.has(e))) && (a = Array.from(n.keys())), a)
})
}
export const getCallPresenceStreamName = (e, t) => (r) => {
const n = getCallState(r).presenceBySwarmId[e]
return n && n.streamByName
? Object.keys(n.streamByName).reduce((e, r) => {
if (e) return e
const a = n.streamByName[r]
return a?.streamId === t ? r : ""
}, "")
: ""
}
export const getScreenStreams = e(
getCallPresenceMemberSwarmIds,
getCallPresenceState,
getCallMediaState,
getCallMyMemberId,
o,
(e, t, n, a, l) => {
const s = []
return (
a && l && s.push({ streamId: l, memberId: a, isLocal: !0 }),
e.forEach((e) => {
const a = t[e],
l = n[e],
o = !!a.streamByName?.[r.SCREEN],
c = l && l.streamByName?.[r.SCREEN]?.id
o && s.push({ streamId: c, memberId: a.memberId, swarmId: e })
}),
s
)
},
)
export const getScreenSharingDisabled = e(getScreenStreams, (e) => !!e.find((e) => !e.isLocal))
export const getHasScreenSharingStreams = (e) => getScreenStreams(e).length > 0
export const getActivePresences = e(
[getCallTopSortedPresences, getActiveCallMemberIds, getCallPresenceSwarmByMemberIds],
(e, t, r) => (t?.length ? Y(e, t, r) : W),
)
export const getIsPresenceOffline = (e) => (t) => {
if (!e) return !1
const { streamByName: r } = getCallState(t).mediaBySwarmId?.[e] || {}
return !Q(t).includes(e) || !(r?.camera || r?.screen)
}
const X = (e) => (t) => getCallState(t).mediaBySwarmId[e]?.streamByName
export const makeGetIsPresenceOffline = (t) =>
e([X(t), Q], (e, r) => !(!t || ((e?.camera || e?.screen) && r.includes(t))))
export const getHasCallMemberConnected = (e) => (t) => !!getCallState(t).connectedMemberIds?.[e]
const Z = (e) => getCallState(e).connectedMemberIds
export const makeGetHasCallMemberConnected = (t) => e([Z], (e) => !!e?.[t])
export const makeGetPositionPreservedActiveSwarmIds = () => {
let t = []
return e([getActivePresences, (e, t) => t], (e, r) => {
const n = e.slice(0, r)
return ((t = K(t, n)), t)
})
}