export default class Activity{constructor(e){this.#e=e,this.#t=setInterval(this.heartbeat.bind(this),15e3),this.#i()}#e;#t;users={};worldTime;#s;queries=new Map;#i(){this.#s=Date.now(),db.Setting.getValue("core.time").then(e=>{if(this.worldTime=Number.isNumeric(e)?Number(e):0,void 0===e)return db.Setting.set("core.time",0)})}get serverTime(){return Date.now()-this.#s}heartbeat(){if(game.world!==this.#e)return void clearInterval(this.#t);if(!game.users)return;const e=Date.now();for(const t of game.users)if(this.users[t.id])if(0===t.sockets.length)this.deactivateUser(t);else{const i=this.users[t.id]??{};!i.idle&&e-i.lastActivityTime>CONST.IDLE_THRESHOLD_MS&&(i.idle=!0,express.io.emit("userActivity",t.id,i))}}activateUser(e){const{express:t,game:i,db:s}=global;return"string"==typeof e&&(e=i.users.find(t=>t.id===e)),e instanceof s.User&&(!(e.id in this.users)&&(this.users[e.id]={active:!0,lastActivityTime:Date.now(),idle:!1},t.io.emit("userActivity",e.id,this.users[e.id]),!0))}deactivateUser(e){const{express:t,db:i}=global;if(!(e instanceof i.User))throw new Error("You must provide a User document instance to the deactivateUser method");return!e.sockets.length&&(e.id in this.users&&(delete this.users[e.id],t.io.emit("userActivity",e.id,{active:!1,idle:!1})),!0)}static socketListeners(e){this._onActivate(e,!0),e.on("disconnect",()=>this._onActivate(e,!1)),e.on("userActivity",(t,i)=>Activity.#r(e,t,i)),e.on("getUserActivity",()=>Activity.#a(e)),e.on("userQuery",(t,i,s,r,a,o)=>{Activity.#o(e,t,i,s,r,a,o)}),e.on("pause",(...t)=>this.pause(e,...t)),e.on("time",Activity.#c.bind(Activity)),e.on("reload",()=>{e.user.can("SETTINGS_MODIFY")&&e.broadcast.emit("reload")})}static _onActivate(e,t){const{game:i}=global;i.ready&&i.activity&&e.user&&(t?i.activity.activateUser(e.user):i.activity.deactivateUser(e.user))}static async#c(e){const{game:t}=global;return t.ready&&t.activity?e({serverTime:t.activity.serverTime,worldTime:t.activity.worldTime}):e({})}static pause(e,t,i){game.ready&&e.user.isGM&&(global.logger.info(`Toggling game pause status to ${t}`),game.paused=t,i.userId=e.user.id,e.broadcast.emit("pause",t,i))}static#r(e,t,i={}){if(!game.ready||!game.activity)return;const s=game.activity.users[t]??={};for(const e of["sceneId","levelId","cursor","ruler","targets","av"])e in i&&(s[e]=i[e]);const r=Date.now();s.lastActivityTime=i.lastActivityTime=r,s.idle=i.idle=!1,e.broadcast.emit("userActivity",t,i)}static async#o(e,t,i,s,r,a,o){const c=e.user;if(!c.hasPermission("QUERY_USER"))return void o({status:"rejected",reason:`User [${c.id}] does not have permission to query users`});const n=game.users.find(e=>e.id===t);if(!n)return void o({status:"rejected",reason:`User [${t}] does not exist or is not active`});let{timeout:d}=a;"number"!=typeof d&&(d=void 0),a={timeout:d},game.activity.queries.set(i,{id:i,name:s,data:r,options:a,sender:c,recipient:n});const u=()=>{o&&(o({status:"rejected",reason:`User [${t}] has disconnected`}),o=void 0,game.activity.queries.delete(i))};e.once("disconnect",u);const m=t=>{o&&(o(t),o=void 0,e.off("disconnect",u),game.activity.queries.delete(i))};void 0!==d?n.sockets.forEach(e=>{e.timeout(d).emit("userQuery",c.id,i,s,r,a,(e,t)=>{m(e?{status:"rejected",reason:e.message}:t)})}):n.sockets.forEach(e=>e.emit("userQuery",c.id,i,s,r,a,m))}static#a(e){if(!game.ready||!game.activity)return;const t=Date.now();for(const[i,s]of Object.entries(game.activity.users)){const r=s.lastActivityTime??t;s.idle=t-r>CONST.IDLE_THRESHOLD_MS,e.emit("userActivity",i,s)}}}