import { Injectable } from "../../Injector/ServiceDecorator";
import { ShoutboxFeatureIfc, ShoutboxIfc } from "./RPCInterface";
import { FrontworkComponent } from "../../Types/FrontworkComponent";
import { TableDefiniton } from "../../Types/Types";
import { IShoutbox, ShoutMessage } from "./Interface";
import { SubscriptionResponse, makeSubResponse } from "rpclibrary";
import * as  CircularBuffer from "circular-buffer";

@Injectable(IShoutbox)
export class Shoutbox
implements FrontworkComponent<ShoutboxIfc, ShoutboxFeatureIfc>, IShoutbox{
    name = "Shoutbox" as "Shoutbox";    

    log: CircularBuffer = new CircularBuffer(500)
    subs = {}

    exportRPCs = () => [
        this.shout,
        this.getFeed,
        {
            name: 'subscribe' as 'subscribe',
            hook: this.subscribe,
            onClose: (subres, rpcName) => {
                this.unsubscribe(subres.uuid)
            }
        }
    ]

    exportRPCFeatures = () => []
    
    getTableDefinitions(): TableDefiniton[] {
        return []
    }

    shout = async (uuid:string, msg: ShoutMessage) : Promise<void> => {
        if(!this.subs[uuid]) return
        this.broadcast(uuid, msg)
        this.log.push(msg)
    }

    private broadcast = (uuid:string, msg: ShoutMessage) => {
        Object.values(this.subs).forEach((cb:any) => {
            try{
                cb(msg)
            }catch(e){
                this.unsubscribe(uuid)
            }
        })
    }

    getFeed = async () : Promise<ShoutMessage[]> => {
        return this.log.toarray()
    }

    subscribe = async (callback) : Promise<SubscriptionResponse> => {
        const resp = makeSubResponse({})
        this.subs[resp.uuid] = callback
        return resp
    }

    unsubscribe = async (uuid: string) => {
        delete this.subs[uuid]
    }
}