const e=require("bare-events"),s=require("b4a");class t{constructor(e){this.value=e,this.prev=null,this.next=null}}class i{constructor(e){this.value=e,this.refs=0,this.gc=null}}class h{constructor(){this.head=null,this.tail=null,this.size=0}add(e){const s=new t(e);return this.tail?(this.tail.next=s,s.prev=this.tail):this.head=s,this.tail=s,this.size++,s}remove(e){e.prev?e.prev.next=e.next:this.head=e.next,e.next?e.next.prev=e.prev:this.tail=e.prev,this.size--}shift(){const e=this.head;return e?(this.remove(e),e.value):null}}class n{constructor(e){this._maxSize=e,this._m=new Map,this._gc=new h}get size(){return this._m.size}maybeEvict(){for(;this._m.size>this._maxSize&&this._gc.size>0;){const e=this._gc.shift();this._m.delete(e)}}set(e,s){const t=this._m.get(e);if(t)return void(t.value=s);const h=new i(s);h.gc=this._gc.add(e),this._m.set(e,h)}get(e){return this._m.get(e)?.value}ref(e){const s=this._m.get(e);s&&(s.refs++>0||(this._gc.remove(s.gc),s.gc=null))}unref(e){const s=this._m.get(e);s&&0!==s.refs&&(--s.refs>0||(s.gc=this._gc.add(e)))}forceGC(e){const s=this._maxSize;this._maxSize=e,this.maybeEvict(),this._maxSize=s}}class o extends e{constructor({size:e=200}={}){super(),this._cache=new n(e)}get size(){return this._cache.size}id(e){}cacheId(e){}diff(e,s){return!0}ref(e){this._cache.ref(e)}unref(e){this._cache.unref(e)}maybeGC(){this._cache.maybeEvict()}getRaw(e){return this._cache.get(this.constructor.cacheId(e))}get(e){return this._cache.get(e)}add(e,s){const t=s?.cacheId||this.constructor.cacheId(this.id(e)),i=this._cache.get(t);return i&&!this.diff(i,e)||(this._cache.set(t,e),this.emit("update",t,e)),t}}class a extends o{static cacheId(e){return s.toString(e,"hex")}id(e){return e.key}diff(e,s){return e.profile.timestamp!==s.profile.timestamp}}class c extends o{static cacheId(e){return s.toString(e,"hex")}id(e){return e.key}diff(e,s){return e.status.isActive!==s.status.isActive||e.status.isIndexing!==s.status.isIndexing||e.profile.name!==s.profile.name}}class r extends o{static cacheId(e){return s.toString(e,"hex")}id(e){return e.roomKey}diff(e,s){return!0}}class d extends o{static cacheId({key:e,seq:t}){return`${s.toString(e,"hex")}-${t}`}id(e){return e.id}diff(e,s){return!0}}class m extends o{static cacheId({key:e,seq:t}){return`${s.toString(e,"hex")}-${t}`}id(e){return e.id}diff(e,s){return!0}}class g extends e{constructor(e){super(),this.view=e,this.status=null,this.member=null,this.devices=[],this.memberKey=null,this.deviceKeys=[],this._clock=0,this._memberId=null,this._deviceIds=[]}_unref(){this._memberId&&this.view.members.unref(this._memberId);for(const e of this._deviceIds)this.view.devices.unref(e)}_ref(){this._memberId&&this.view.members.ref(this._memberId);for(const e of this._deviceIds)this.view.devices.ref(e)}_inflate(){this.member=this.view.members.get(this._memberId),this.devices=this._deviceIds.map(e=>this.view.devices.get(e))}onMemberChanged(){this._inflate(),this.emit("update:member"),this.emit("update")}onDeviceChanged(){this._inflate(),this.emit("update:device"),this.emit("update")}onReset({memberKey:e,deviceKeys:s,status:t}){this._unref(),this.status=t,this.memberKey=e,this.deviceKeys=s,this._memberId=a.cacheId(this.memberKey),this._deviceIds=s.map(e=>c.cacheId(e)),this._ref(),this._inflate(),this.emit("reset")}onWant(e){this._clock=e}onHave(e){e===this._clock&&(this.emit("have",e),this.emit("update"))}onCancel(e){e===this._clock&&(this._clock=0)}}class u{constructor(e,s,t){this.id=e,this.cacheId=s,this.role=t.role,this.digest=t.digest,this.config=t.config,this.message=t.message,this.messageId=t.messageId,this.messageCacheId=d.cacheId(this.messageId)}with(e){return new u(this.id,this.cacheId,{...this,...e})}}class l extends e{constructor(e){super(),this.view=e}ref(e){this.view.rooms.ref(e.cacheId),e.messageCacheId&&this.view.messages.ref(e.messageCacheId)}unref(e){this.view.rooms.unref(e.cacheId),e.messageCacheId&&this.view.messages.unref(e.messageCacheId)}onRoleChanged({id:e,role:s}){const t=this.view.rooms.get(e);if(!t)return;const i=t.with({role:s});this.view.rooms.add(i,{cacheId:e}),this.emit("update:role",i)}onDigestChanged({id:e,digest:s}){const t=this.view.rooms.get(e);if(!t)return;const i=t.with({digest:s});this.view.rooms.add(i,{cacheId:e}),this.emit("update:digest",i)}onConfigChanged({id:e,config:s}){const t=this.view.rooms.get(e);if(!t)return;const i=t.with({config:s});this.view.rooms.add(i,{cacheId:e}),this.emit("update:config",i)}onLastMessageChanged({id:e,messageId:s}){const t=this.view.rooms.get(e);if(!t)return;const i=d.cacheId(s),h=this.view.messages.get(i),n=t.with({messageId:s,messageCacheId:i,message:h});this.view.rooms.add(n,{cacheId:e}),this.emit("update:message",n)}onAdd(e,{cacheId:t=null}={}){t||(t=s.toString(e.id,"hex"));const i=d.cacheId(e.messageId),h=(this.view.messages.get(i),{role:e.role,digest:e.digest,config:e.config,messageId:e.messageId,messageCacheId:i,message:this.view.messages.get(i)});let n=this.view.rooms.get(t);return n=n?n.with(h):new u(e.id,t,h),this.view.rooms.add(n,{cacheId:t}),this.emit("update:reset",n),n}}class f{constructor(e,s,t){this.id=e,this.cacheId=s,this.role=t.role,this.chat=t.chat,this.member=t.member,this.reactions=t.reactions,this.memberKey=t.memberKey,this.memberId=t.memberId}with(e){return new f(this.id,this.cacheId,{...this,...e})}}class I extends e{constructor(e){super(),this.view=e}ref(e){this.view.messages.ref(e.cacheId),e.memberId&&this.view.members.ref(e.memberId)}unref(e){this.view.messages.unref(e.cacheId),e.memberId&&this.view.members.unref(e.memberId)}onChatChanged({chat:e}){const s=d.cacheId(e.id),t=this.view.messages.get(s);if(!t)return;const i=t.with({chat:e});this.view.messages.add(i,{cacheId:s}),this.emit("update:chat",{chat:e,messages:[i]})}onRoleChanged({ids:e,role:s}){const t=[];for(const i of e){const e=d.cacheId(i),h=this.view.messages.get(e);if(!h)continue;const n=h.with({role:s});this.view.messages.add(n,{cacheId:e}),t.push(n)}t.length>0&&this.emit("update:role",{ids:e,role:s,messages:t})}onMemberChanged({ids:e,memberKey:s}){const t=this.view.members.get(a.cacheId(s));if(!t)return;const i=[];for(const s of e){const e=d.cacheId(s),h=this.view.messages.get(e);if(!h)continue;const n=h.with({member:t});this.view.messages.add(n,{cacheId:e}),i.push(n)}i.length>0&&this.emit("update:member",{ids:e,memberKey:s,messages:i})}onReactionsChanged({id:e,reactions:s}){const t=d.cacheId(e),i=this.view.messages.get(t);if(!i)return;const h=i.with({reactions:s});this.view.messages.add(h,{cacheId:t}),this.emit("update:reactions",{id:e,reactions:s,messages:[h]})}onAdd(e,{cacheId:s=null}={}){s||(s=d.cacheId(e.chat.id));const t=a.cacheId(e.memberKey),i=e.memberKey;let h=this.view.messages.get(s);if(!h){const n={reactions:this.view.reactions.get(s),member:this.view.members.get(t),chat:e.chat,role:e.role,memberKey:i,memberId:t};h=new f(e.chat.id,s,n),this.view.messages.add(h,{cacheId:s})}return this.emit("update:reset",h),h}}class _ extends e{constructor(e){super(),this.view=e,this.pendingInvitations=[],this.identityJoinRequests=[],this.clock=0,this._pending=!0,this._invitationIds=new Set,this._joinRequestIds=new Set}onWant(e){this.clock=e,this._pending=!0}onHave(e){e===this.clock&&(this._pending=!1,this.emit("have",e),this.emit("update"))}onCancel(e){e===this.clock&&(this.clock=0,this._pending=!0)}onReset({pendingInvitations:e,identityJoinRequests:t}){const i=new Set(e.map(e=>s.toString(e.id,"hex"))),h=new Set(t.map(e=>s.toString(e.deviceKey,"hex"))),n=!p(this._invitationIds,i),o=!p(this._joinRequestIds,h);(n||o)&&(this.pendingInvitations=e,this.identityJoinRequests=t,this._invitationIds=i,this._joinRequestIds=h,this.emit("reset"),this._pending||this.emit("update"))}}class v extends e{constructor(e){super(),this.view=e,this.rooms=null,this.keys=null,this.start=0,this.end=0,this.total=0,this.clock=0,this._pending=!0,this._ids=null,this._cacheIdSet=null}_unref(){if(this.rooms)for(const e of this.rooms)e&&this.view.roomInfo.unref(e)}_ref(){if(this._ids)for(const e of this._ids){this.view.rooms.ref(e);const s=this.view.rooms.get(e);s?.messageCacheId&&this.view.messages.ref(s.messageCacheId)}}_refreshRooms(){this.rooms=this._ids.map(e=>this.view.rooms.get(e))}onRoomChanged(e,s){this._cacheIdSet&&this._cacheIdSet.has(e.cacheId)&&(this._unref(),this._refreshRooms(),this._ref(),this.emit("update:"+s,e),this._pending||this.emit("update"))}onWant(e,s,t){this.clock=e,this.start=s,this.end=t,this._pending=!0}onHave(e){e===this.clock&&(this._pending=!1,this.emit("have",e),this.emit("update"))}onCancel(e){e===this.clock&&(this.start=0,this.end=0,this._pending=!0,this._cacheIdSet=null)}onReset({keys:e,start:t,end:i,total:h}){const n=this._ids;if(this.keys=e,this.start=t,this.end=i,this.total=h,this._ids=e.map(e=>s.toString(e,"hex")),this._cacheIdSet=new Set(this._ids),this._ref(),n)for(const e of n){const s=this.view.rooms.get(e);s&&this.view.roomInfo.unref(s)}this._refreshRooms(),this.emit("reset"),this._pending||this.emit("update")}}class w extends e{constructor(e){super(),this.view=e,this.messages=null,this.ids=null,this.room=null,this.roomKey=null,this.start=0,this.end=0,this.total=0,this.isBottom=!1,this.clock=0,this._pending=!0,this._ids=null,this._cacheIdSet=null,this._roomCacheId=null}_unref(){if(this._cacheIds)for(const e of this._cacheIds){const s=this.view.messages.get(e);s&&this.view.messageInfo.unref(s)}}_ref(){if(this._cacheIds)for(const e of this._cacheIds){this.view.messages.ref(e);const s=this.view.messages.get(e);s?.memberId&&this.view.members.ref(s.memberId)}}_refreshMessages(){this.messages=this._cacheIds.map(e=>this.view.messages.get(e))}_refreshRoom(){this.room=this._roomCacheId?this.view.rooms.get(this._roomCacheId):null}onRoomChanged(e,s){this._roomCacheId&&this._roomCacheId===e.cacheId&&(this._refreshRoom(),this.emit("update:room:"+s,this.room),this.emit("update:room",this.room),this._pending||this.emit("update"))}onMessagesChanged(e,s){const t=e.filter(e=>this._cacheIdSet?.has(e.cacheId));0!==t.length&&(this._unref(),this._refreshMessages(),this._ref(),this.emit("update:"+s,t),this._pending||this.emit("update"))}onWant(e,s,t,i,h){this.clock=e,this.roomKey=s,this._roomCacheId=r.cacheId(s),this.start=t,this.size=i,this.isBottom=h,this._pending=!0}onHave(e){e===this.clock&&(this._pending=!1,this.emit("have",e),this.emit("update"))}onCancel(e){e===this.clock&&(this.room=null,this.roomKey=null,this.start=0,this.end=0,this._pending=!0,this._roomCacheId=null,this._cacheIdSet=null)}onReset({ids:e,roomKey:s,start:t,size:i,total:h,isBottom:n}){const o=this._cacheIds;if(this.ids=e,this.roomKey=s,this.start=t,this.size=i,this.total=h,this.isBottom=n,this._roomCacheId=r.cacheId(s),this._cacheIds=e.map(e=>d.cacheId(e)),this._cacheIdSet=new Set(this._cacheIds),this._ref(),o)for(const e of o){const s=this.view.messages.get(e);s&&this.view.messageInfo.unref(s)}this._refreshMessages(),this._refreshRoom(),this.emit("reset"),this._pending||this.emit("update")}}function p(e,s){if(e.size!==s.size)return!1;for(const t of e)if(!s.has(t))return!1;return!0}module.exports=class{constructor(){this.members=new a,this.devices=new c,this.reactions=new m,this.messages=new d,this.rooms=new r,this.identity=new g(this),this.pairing=new _(this),this.lobby=new v(this),this.chat=new w(this),this.roomInfo=new l(this),this.messageInfo=new I(this),this.roomInfo.on("update:reset",e=>{this.chat.onRoomChanged(e,"reset")}),this.roomInfo.on("update:role",e=>{this.lobby.onRoomChanged(e,"role"),this.chat.onRoomChanged(e,"role")}),this.roomInfo.on("update:digest",e=>{this.lobby.onRoomChanged(e,"digest"),this.chat.onRoomChanged(e,"digest")}),this.roomInfo.on("update:config",e=>{this.lobby.onRoomChanged(e,"config"),this.chat.onRoomChanged(e,"config")}),this.roomInfo.on("update:message",e=>{this.lobby.onRoomChanged(e,"message")}),this.messageInfo.on("update:chat",({messages:e})=>this.chat.onMessagesChanged(e,"chat")),this.messageInfo.on("update:role",({messages:e})=>this.chat.onMessagesChanged(e,"role")),this.messageInfo.on("update:member",({messages:e})=>this.chat.onMessagesChanged(e,"member")),this.messageInfo.on("update:reactions",({messages:e})=>this.chat.onMessagesChanged(e,"reactions"))}};