import {
all as e,
call as o,
delay as t,
fork as i,
getContext as a,
put as r,
select as l,
spawn as d,
take as n,
takeLatest as m,
takeLeading as s,
} from "redux-saga/effects"
import { FEATURES as c } from "@holepunchto/keet-core/features"
import { apiCall as f } from "../../../api/core"
import { getCoreBackend as y } from "../../../backend"
import { chatDeleteMessageHandler as u, createMessageId as p } from "../../chat"
import { APP_CONTEXT_KEY as I } from "../../constants"
import { taskError as g, taskErrorSaga as S } from "../../error"
import { last as b } from "../../lib/array"
import { isEmpty as h } from "../../lib/object"
import {
fetchFileEntryWithPreviews as R,
FILE_PREVIEW_NAME_PREFIX as A,
fileSaga as L,
getFileEntryById as E,
getFileId as F,
parseCoreFile as D,
removeFileEntries as C,
updateFileEntry as v,
} from "../../media/file"
import { ROOM_AVATAR_UPLOAD_KEY as x, ROOM_INFO_FILES_LOAD_LIMIT as _ } from "../room.constant"
import { sanitizeRoomDescription as O } from "../room.model"
import {
ROOM_INFO_FILES_LOADING_STATUS as N,
ROOM_SETTING as T,
ROOM_SETTING_API_SYSTEM_KEY_MAP as k,
} from "./room-main.constant"
import {
deleteRoomFile as B,
getRoomInfoFilesInView as H,
getRoomInfoFilesLoadingStatusByTab as j,
getRoomInfoFilesLteByTab as w,
getRoomInfoFilesTab as G,
loadMoreFiles as K,
makeGetRoomInfoFileById as M,
removeRoomAvatar as P,
resetRoomInfoFiles as U,
setRoomInfoFiles as W,
setRoomInfoFilesInViewRange as q,
setRoomInfoFilesLoadingStatus as z,
setRoomInfoFilesTab as J,
updateRoomAvatar as Q,
updateRoomCanCall as V,
updateRoomDescription as X,
updateRoomSetting as Y,
} from "./room-main.reducer"
import { apiSubscribeSaga as Z } from "../../lib"
import { getRoomFeatureSupported as $ } from "../room.feature"
export function* updateRoomConfigSaga(e, o, t) {
try {
const i = y()
yield f(i.updateConfig, e, o, t)
} catch (e) {
yield g("updateRoomConfigSaga", e)
}
}
export function* updateRoomAvatarSaga({ roomId: e }) {
try {
const { uploads: o } = yield a(I),
t = y(),
i = { small: null, medium: null },
r = o.get(x)
if (h(r)) return void o.del(x)
if (r.small) {
const {
base64: e,
metadata: { mimetype: o, dimensions: t },
} = r.small
i.small = { pointer: { inlined: e }, metadata: { mimetype: o, dimensions: t } }
}
if (r.medium) {
const {
base64: e,
metadata: { mimetype: o, dimensions: t },
} = r.medium
i.medium = { pointer: { inlined: e }, metadata: { mimetype: o, dimensions: t } }
}
if (r.large) throw new Error("Not yet supported")
;(yield f(t.updateConfig, e, "avatar", i), o.del(x))
} catch (e) {
yield r(g("updateRoomAvatarSaga", e))
}
}
function* ee({ roomId: e }) {
try {
const o = y(),
t = yield f(o.getRoomInfo, e),
i = t?.config
if (!i.avatar.small) return
yield f(o.updateConfig, e, "avatar", { small: null, medium: null })
} catch (e) {
yield r(g("removeRoomAvatarSaga", e))
}
}
function* oe({ roomId: o, fileStatsChannel: i }) {
const a = {}
function* r() {
yield t(250)
const r = yield l(H),
n = r.map((e) => e.id)
Object.keys(a).forEach((e) => {
n.includes(e) || (a[e].cancel(), delete a[e])
})
const m = r.filter((e) => !a[e.id]),
s = yield e(
m.map((e) => {
const { id: t } = e
return d(L, { roomId: o, fileId: t, fileStatsChannel: i })
}),
)
m.forEach((e, o) => {
a[e.id] = s[o]
})
}
try {
for (;;) (yield n([q]), yield r())
} finally {
Object.values(a).forEach((e) => e?.cancel())
}
}
export function* handleSubscribedRoomFiles({ files: e, tab: t, roomId: i }) {
const a = []
for (const t of e) {
const { metadata: e, pointer: d } = t || {}
if (!e || !d || e.isPreview || e.name?.startsWith(A)) continue
const n = F(d),
m = p({ id: t.messageId })
let s = yield l(E, n)
if (!s) {
if (t.entry.cleared) {
const e = yield o(R, t, i)
s = D({ ...t, entry: e })
} else s = D(t)
yield r(v(s))
}
a.push({ ...s, messageId: m })
}
const d = b(e)?.id,
n = d > 1 ? N.LOADED : N.ALL_LOADED,
m = d > 1 ? d - 1 : null
yield r(W({ tab: t, files: a, nextLte: m, nextLoadingStatus: n }))
}
export function* subscribeRoomFilesSaga({ roomId: e }) {
const o = yield l(G),
t = yield l(j(o))
if ([N.LOADING, N.ALL_LOADED].includes(t)) return
yield r(z({ tab: o, status: N.LOADING }))
const i = { limit: _, type: o },
a = yield l(w(o))
;(a > 0 && (i.lte = a),
yield Z(
[y().subscribeFiles, e, i],
function* (t) {
yield handleSubscribedRoomFiles({ files: t, roomId: e, tab: o })
},
{
onError: function* (e) {
;(yield S("subscribeRoomFilesSaga", e), yield r(z({ tab: o, status: N.ERROR })))
},
},
))
}
export function* updateRoomSettingSaga({ roomId: e }, { payload: { key: o, value: t } }) {
try {
const i = yield l($(e, c.DISABLE_FILE_ATTACHMENTS))
if (o === T.IS_ATTACHMENT_DISABLED && !i) return
const a = yield l($(e, c.DISABLE_LINKS))
if (o === T.IS_LINK_DISABLED && !a) return
const r = y()
yield f(r.updateRoomSettings, e, k[o], { [o]: t })
} catch (e) {
yield g("UpdateRoomSettingSaga", e)
}
}
export function* roomFilesInitialFetchSaga({ roomId: e }) {
const t = yield l(G)
;(yield r(U({ tab: t })), yield o(subscribeRoomFilesSaga, { roomId: e }))
}
export function* roomFilesDeleteFileHandler({ roomId: e }, { payload: o }) {
try {
const { fileId: t } = o,
i = M(t),
a = yield l(i)
if (!a) return
;(yield u(e, a.messageId), yield r(C({ fileIds: [t], messageIds: [a.messageId] })))
} catch (e) {
yield S("deleteFileEntry", e)
}
}
export function* roomInfoSaga({ roomId: e, fileStatsChannel: o }) {
;(yield s(Q, updateRoomAvatarSaga, { roomId: e }),
yield s(P, ee, { roomId: e }),
yield m(K, subscribeRoomFilesSaga, { roomId: e }),
yield m(J, roomFilesInitialFetchSaga, { roomId: e }),
yield s(Y, updateRoomSettingSaga, { roomId: e }),
yield s(V, function* (o) {
yield updateRoomConfigSaga(e, "canCall", o.payload)
}),
yield s(X, function* (o) {
const t = O(o.payload)
yield updateRoomConfigSaga(e, "description", t)
}),
yield r(U()),
yield i(oe, { roomId: e, fileStatsChannel: o }),
yield s(B, roomFilesDeleteFileHandler, { roomId: e }))
}