import { isEmpty as t } from "../../lib/array"
import { chatInit as e } from "../init"
import { setChatMessageCount as s } from "../message"
import { CHAT_EMPTY_COUNT as i } from "../chat.constant"
import {
setChatListViewMode as o,
setChatListViewPaused as n,
setChatMessageAnchor as r,
setChatMessagesInView as a,
setChatListViewStopAnchor as c,
setChatListViewPeerSeenSeq as l,
updateAnchorStatus as u,
incChatListAnchorRetryCount as w,
setChatListViewStartSeenSeq as m,
} from "./list-view.action"
import {
VIEW_MODE as d,
ANCHOR_STATUS as V,
CHAT_LIST_VIEW_CONFIG as p,
CHAT_LIST_VIEW_STATE_KEY as E,
ANCHOR_LOADED_RETRY_COUNT as S,
} from "./list-view.constant"
import {
calcStartLastSeen as f,
createAnchorToBottom as D,
createAnchorToMessage as h,
isAnchorInView as y,
isAnchorScrolling as R,
isChatListLive as g,
shouldStartHistory as b,
} from "./list-view.model"
import { sharedCoreMessagesUpdate as q } from "../../api/data.action"
export const findMessageBySeq = ({ message: t }, e) => {
const { byId: s, ids: i } = t
for (let t = 0; t < i.length; t += 1) {
const o = s[i[t]]
if (o?.seq === e) return o
}
return null
}
export const chatListViewInViewReducer = (e, { payload: s }) => {
const {
message: { count: o, byId: n, ids: r, seqLoaded: a },
listView: { inView: c, anchor: l, mode: u },
} = e
if (o === i || t(r)) return e
let { top: w, bottom: m } = s
if (!Number.isInteger(w)) {
const { topId: t } = s
t && (w = n[t]?.seq)
}
if (!Number.isInteger(m)) {
const { bottomId: t } = s
t && (m = n[t]?.groupSeq ?? n[t]?.seq)
}
if (!Number.isInteger(w) || !Number.isInteger(m)) return e
if (c.top === w && c.bottom === m)
return l && R(l.status) && y(c, l, o)
? { ...e, listView: { ...e.listView, anchor: { ...l, status: V.RENDERED } } }
: e
const p = { top: w, bottom: m }
let E = l
l && R(l.status) && y(p, l, o) && (E = { ...l, status: V.RENDERED })
let S = u
if (g(u) && c.bottom !== m && (!E || E.status === V.RENDERED)) {
const t = ("down" == (c.bottom - m > 0 ? "up" : "down") || m === a.bottom) && u === d.LATEST
S = m + 1 >= o || t ? d.LATEST : d.HISTORY
}
return { ...e, listView: { ...e.listView, inView: p, anchor: E, mode: S } }
}
export const chatListViewReducer = (t, i) => {
switch (i.type) {
case n.type: {
const {
message: e,
listView: { mode: s, inView: o, lastSeenSeq: n },
} = t,
r = i.payload
if (r || !g(s)) return { ...t, listView: { ...t.listView, paused: r, anchor: null } }
const { count: a, ids: c } = e,
l = f({ lastSeenSeq: n, count: a }),
u = findMessageBySeq(t, n),
w = u && b({ startSeq: l, count: a }),
m = w
? h({ messageId: u.id, seq: l, status: o.bottom === l ? V.RENDERED : V.LOADED })
: D({ status: o.bottom === a - 1 ? V.RENDERED : V.LOADED, messageId: c[0] })
return {
...t,
listView: {
...t.listView,
startLastSeen: l,
mode: w ? d.HISTORY : d.LATEST,
anchor: m,
stopAnchor: !1,
paused: !1,
},
}
}
case q.type: {
const {
message: e,
listView: {
mode: s,
startSeq: i,
inView: o,
anchor: n,
stopAnchor: r,
lastSeenSeq: a,
paused: c,
},
} = t
if (s === d.FRESH_LOADING) {
const { count: s, ids: n } = e,
l = findMessageBySeq(t, i),
u = l && b({ startSeq: i, count: s }),
w = f({ lastSeenSeq: a, count: s }),
m = u
? h({ messageId: l.id, seq: i, status: o.bottom === i ? V.RENDERED : V.LOADED })
: D({ status: o.bottom === s - 1 ? V.RENDERED : V.LOADED, messageId: n[0] })
return {
...t,
listView: {
...t.listView,
startLastSeen: w,
mode: u || r ? d.HISTORY : d.LATEST,
anchor: r || c ? null : m,
stopAnchor: !1,
},
}
}
if (s === d.LATEST) {
const { byId: s, count: i } = e,
n = i - 1
if (o.bottom > 0 && o.bottom === n) return t
const r = Object.values(s).find((t) => t.seq === n)
if (!r) {
const e = t.listView.anchor
return e?.lastMessage && e.status !== V.ASKED
? { ...t, listView: { ...t.listView, anchor: { ...e, status: V.ASKED } } }
: t
}
return {
...t,
listView: { ...t.listView, anchor: c ? null : D({ status: V.LOADED, messageId: r.id }) },
}
}
if (t.listView.anchor?.status === V.ASKED) {
const {
message: { ids: e, seqLoaded: s, count: i },
} = t
let o
if (
((o = n.lastMessage
? s.bottom === i - 1
? e[0]
: ""
: e.find((t) => t === n.messageId) || ""),
o)
)
return {
...t,
listView: {
...t.listView,
anchor: { ...n, messageId: o, status: V.LOADED, retryCountProcessed: S },
},
}
}
return t
}
case o.type: {
const e = i.payload,
{ mode: s } = t.listView
return e === s || (g(e) && !g(s)) ? t : { ...t, listView: { ...t.listView, mode: e } }
}
case r.type: {
const { mode: e, anchor: s, inView: o } = t.listView,
{ message: n } = t,
r = i.payload
if (!g(e)) return { ...t, listView: { ...t.listView, anchor: r } }
let a = e
if (r) {
const { lastMessage: e, seq: s } = r
if (e) a = d.LATEST
else {
const {
message: { count: e },
} = t
a = s + 1 >= e ? d.LATEST : d.HISTORY
}
} else s && s.status !== V.RENDERED && o.bottom !== n.count - 1 && (a = d.HISTORY)
return { ...t, listView: { ...t.listView, anchor: r, mode: a } }
}
case u.type: {
const e = i.payload,
{ anchor: s } = t.listView
if (!s || s?.status === e || s?.status === V.RENDERED) return t
const o = { ...s, status: e }
return { ...t, listView: { ...t.listView, anchor: o } }
}
case s.type: {
const {
message: { count: e },
listView: { startSeq: s, mode: i, inView: o, anchor: n, lastSeenSeq: r, paused: a },
} = t
if (0 === e)
return { ...t, listView: { ...t.listView, mode: d.LATEST, inView: { top: 0, bottom: 0 } } }
if (-1 === s || s + 1 > e) return { ...t, listView: { ...t.listView, startSeq: e - 1 } }
const c = r === s && !b({ count: e, startSeq: s })
if (i === d.RESTORE_LAST && c) return { ...t, listView: { ...t.listView, startSeq: e - 1 } }
const l = n && n.status !== V.RENDERED
return i === d.LATEST && !l && e > o.bottom + 1 && !a
? { ...t, listView: { ...t.listView, anchor: D() } }
: t
}
case w.type: {
const { anchor: e } = t.listView
if (!e || !R(e.status)) return t
const s = { ...e, retryCountProcessed: e.retryCountProcessed + 1 }
return { ...t, listView: { ...t.listView, anchor: s } }
}
case a.type:
return chatListViewInViewReducer(t, i)
case e.type: {
const e = i.payload?.[E]
return e ? { ...t, listView: { ...t.listView, config: { ...p, ...e } } } : t
}
case c.type: {
const e = i.payload
return e === t.listView.stopAnchor ? t : { ...t, listView: { ...t.listView, stopAnchor: e } }
}
case l.type:
return { ...t, listView: { ...t.listView, peerSeenSeq: i.payload } }
case m.type:
return { ...t, listView: { ...t.listView, startLastSeen: i.payload } }
default:
return t
}
}