import Actions from "./enum/Actions.js"
import Codes from "./enum/Codes.js"
import util from "./util.js"
import Logger from "./Logger.js"

const logger = new Logger('events')
export default class EventsManager extends EventEmitter {
    constructor() {
        super(...arguments);
        E(this, "events", new Map);
        E(this, "specialEvents", new Map)
    }
    remove(e, t, r, n) {
        if (this.specialEvents.has(e) && !n && t === Codes.Success)
            return;
        this.events.get(e) && (this.emit(e, {
            code: t,
            data: r
        }),
        this.events.delete(e),
        this.specialEvents.delete(e))
    }
    async track(e, t) {
        const r = e.traceId;
        this.emitTraceIdToDecoder(e);
        const {sampleRate: n, noReport: o=!1, special: a} = t || {};
        if (n && Math.random() > n)
            return Promise.resolve();
        const s = Actions[e.event] + "Action"
          , l = e.tag;
        this.events.set(r, !0),
        a && this.specialEvents.set(r, !0);
        const u = Date.now();
        let c = null;
        return new Promise((h,f)=>{
            if (o)
                return this.off(r),
                this.events.delete(r),
                h(void 0);
            this.on(r, ({code: _, data: g, msg: m})=>{
                if (_ === Codes.Success)
                    h(g),
                    this.off(r),
                    logger.infoAndReportMeasurement({
                        metric: s,
                        tag: l,
                        extra: e.extra,
                        startTime: u,
                        traceId: r
                    });
                else {
                    if (_ === Codes.ActionMaybeDelay)
                        return;
                    if (_ === Codes.DoActionBlocked && e.event === Actions.Rotation) {
                        logger.debug(s + " response code: " + _);
                        return
                    }
                    const v = util.getErrorByCode(_)
                      , y = new v(m);
                    this.off(r),
                    f(y),
                    this.emit("actionResponseError", {
                        error: y,
                        event: e,
                        tag: l
                    }),
                    logger.infoAndReportMeasurement({
                        metric: s,
                        tag: l,
                        extra: e.extra,
                        error: y,
                        startTime: u,
                        traceId: r
                    })
                }
            }
            );
            const d = e.timeout || 2e3;
            c = window.setTimeout(()=>{
                if (c && clearTimeout(c),
                !this.events.get(r))
                    return;
                const _ = new ActionResponseTimeoutError(`${s} timeout in ${d}ms`);
                this.emit("actionResponseTimeout", {
                    error: _,
                    event: e,
                    tag: l
                }),
                f(_),
                this.events.delete(r),
                this.off(r),
                logger.infoAndReportMeasurement({
                    metric: s,
                    tag: l,
                    extra: e.extra,
                    error: _,
                    startTime: u,
                    traceId: r
                })
            }
            , d)
        }
        )
    }
    emitTraceIdToDecoder(e) {
        if (e.event === Actions.Rotation || e.event === Actions.Clicking || e.event === Actions.GetOnVehicle || e.event === Actions.GetOffVehicle) {
            const t = {
                [Actions.Rotation]: "Rotation",
                [Actions.GetOnVehicle]: "GetOnVehicle",
                [Actions.GetOffVehicle]: "GetOffVehicle",
                [Actions.Clicking]: "MoveTo"
            };
            this.emit("traceId", {
                traceId: e.traceId,
                timestamp: Date.now(),
                event: t[e.event]
            })
        }
    }
}

const eventsManager = new EventsManager();
export { eventsManager };