"use strict";
Object.defineProperty(exports, "__esModule", {
    value: true
});
Object.defineProperty(exports, "MoonrakerWebsocketAdapter", {
    enumerable: true,
    get: function() {
        return MoonrakerWebsocketAdapter;
    }
});
const _serverconstants = require("../../server.constants");
const _urlutils = require("../../utils/url.utils");
const _octoprintwebsocketadapter = require("../octoprint/octoprint-websocket.adapter");
const _moonrakerconstants = require("./constants/moonraker.constants");
const _socketstatetype = require("../../shared/dtos/socket-state.type");
const _apistatetype = require("../../shared/dtos/api-state.type");
const _prettyprintutils = require("../../utils/pretty-print.utils");
const _lodash = /*#__PURE__*/ _interop_require_default(require("lodash"));
const _printerapiinterface = require("../printer-api.interface");
const _websocketrpcextendedadapter = require("../../shared/websocket-rpc-extended.adapter");
const _normalizeurl = require("../../utils/normalize-url");
function _interop_require_default(obj) {
    return obj && obj.__esModule ? obj : {
        default: obj
    };
}
class MoonrakerWebsocketAdapter extends _websocketrpcextendedadapter.WebsocketRpcExtendedAdapter {
    moonrakerClient;
    eventEmitter2;
    configService;
    serverVersion;
    printerType = 1;
    socketState = _socketstatetype.SOCKET_STATE.unopened;
    lastMessageReceivedTimestamp = null;
    stateUpdated = false;
    stateUpdateTimestamp = null;
    apiStateUpdated = false;
    apiStateUpdateTimestamp = null;
    apiState = _apistatetype.API_STATE.unset;
    login;
    printerId;
    refreshPrinterObjectsInterval;
    printerObjects = {
        eventtime: null,
        status: null
    };
    socketURL;
    constructor(loggerFactory, moonrakerClient, eventEmitter2, configService, serverVersion){
        super(loggerFactory), this.moonrakerClient = moonrakerClient, this.eventEmitter2 = eventEmitter2, this.configService = configService, this.serverVersion = serverVersion;
        this.logger = loggerFactory(MoonrakerWebsocketAdapter.name);
    }
    get _debugMode() {
        return this.configService.get(_serverconstants.AppConstants.debugSocketStatesKey, _serverconstants.AppConstants.defaultDebugSocketStates) === "true";
    }
    get subscriptionObjects() {
        return {
            pause_resume: [],
            idle_timeout: [],
            print_stats: [],
            heaters: [],
            heater_bed: [],
            extruder: [],
            display_status: [],
            webhooks: [],
            virtual_sdcard: [],
            gcode_move: [],
            stepper_enable: [],
            fan: [],
            motion_report: [],
            system_stats: []
        };
    }
    needsReopen() {
        return false;
    }
    needsSetup() {
        return this.socketState === _socketstatetype.SOCKET_STATE.unopened;
    }
    needsReauth() {
        return false;
    }
    async reauthSession() {}
    registerCredentials(socketLogin) {
        const { printerId, loginDto } = socketLogin;
        this.printerId = printerId;
        this.login = loginDto;
        const httpUrlString = (0, _normalizeurl.normalizeUrl)(this.login.printerURL);
        const httpUrl = new URL(httpUrlString);
        const httpUrlPath = httpUrl.pathname;
        const wsUrl = (0, _urlutils.httpToWsUrl)(httpUrlString);
        wsUrl.pathname = (httpUrlPath ?? "/") + "websocket";
        this.socketURL = wsUrl;
    }
    open() {
        if (this.socket) {
            throw new Error(`Socket already exists by printerId, ignoring open request`);
        }
        super.open(this.socketURL);
    }
    close() {
        clearInterval(this.refreshPrinterObjectsInterval);
        super.close();
    }
    async setupSocketSession() {
        this.resetSocketState();
        await this.moonrakerClient.getApiVersion(this.login).catch((e)=>{
            this.setSocketState("aborted");
            this.logger.error(`Printer (${this.printerId}) network or transport error, marking it as unreachable; ${e}`);
            this.setApiState("noResponse");
            throw e;
        });
        this.setApiState(_apistatetype.API_STATE.responding);
        await this.updateCurrentStateSafely();
        if (this.refreshPrinterObjectsInterval) {
            clearInterval(this.refreshPrinterObjectsInterval);
        }
        this.refreshPrinterObjectsInterval = setInterval(async ()=>{
            await this.updateCurrentStateSafely();
        }, 15000);
    }
    emitEventSync(event, payload) {
        if (!this.eventEmittingAllowed) {
            return;
        }
        this.eventEmitter2.emit((0, _moonrakerconstants.moonrakerEvent)(event), {
            event,
            payload,
            printerId: this.printerId
        });
    }
    resetSocketState() {
        this.setSocketState("unopened");
        this.setApiState("unset");
    }
    isClosedOrAborted() {
        return this.socketState === _socketstatetype.SOCKET_STATE.closed || this.socketState === _socketstatetype.SOCKET_STATE.aborted;
    }
    async afterOpened(_) {
        this.setSocketState(_socketstatetype.SOCKET_STATE.opened);
        const response = await this.sendRequest({
            jsonrpc: "2.0",
            method: "server.connection.identify",
            params: {
                client_name: "FDM Monster",
                version: this.serverVersion,
                type: "other",
                url: _serverconstants.AppConstants.githubUrl
            },
            id: 1
        });
        try {
            const query = this.subscriptionObjects;
            const result = await this.moonrakerClient.postSubscribePrinterObjects(this.login, response.result.connection_id, query);
            this.printerObjects = result.data.result;
            await this.emitCurrentEvent(this.printerObjects);
        } catch (e) {
            const ae = e;
            if (ae.isAxiosError) {
                if (ae.response?.status === 503) {
                    this.logger.warn(`Klipper host issue ${(0, _prettyprintutils.PP)(ae.response.data?.error?.message)}`);
                } else if (ae.response?.status === 404) {
                    this.logger.error("Error while afterOpened (404) - usually this means Moonraker is still starting");
                }
                this.setApiState(_apistatetype.API_STATE.noResponse);
                return;
            }
            this.logger.error("Unknown error while afterOpened");
            this.setApiState(_apistatetype.API_STATE.noResponse);
        }
    }
    async onEventMessage(event) {
        this.lastMessageReceivedTimestamp = Date.now();
        if (this.socketState !== _socketstatetype.SOCKET_STATE.authenticated) {
            this.setSocketState("authenticated");
        }
        const eventName = event.method;
        if (this._debugMode) {
            this.logger.log(`RX Msg ${eventName} ${JSON.stringify(event.params)?.substring(0, 80)}...`);
        }
        const payload = event.params?.length ? event.params[0] : undefined;
        if (eventName === "notify_service_state_changed") {
            if (!event.params) {
                this.logger.error("Received 'notify_service_state_changed' but service indicators params were undefined");
                return;
            }
            const serviceChanged = event.params[0];
            if (serviceChanged.klipper?.active_state || serviceChanged.klipper_mcu?.active_state || serviceChanged.moonraker?.active_state) {
                this.logger.log("Received notify_service_state_changed, reloading Moonraker printer objects");
                await this.setupSocketSession();
            }
            return;
        }
        if (eventName === "notify_klippy_ready") {
            this.logger.log("Received notify_klippy_ready, reloading Moonraker printer objects");
            return await this.setupSocketSession();
        }
        if (eventName === "notify_klippy_disconnected") {
            this.logger.log("Received notify_klippy_disconnected, reloading Moonraker printer objects");
            return await this.setupSocketSession();
        }
        if (eventName === "notify_klippy_shutdown") {
            this.logger.log("Received notify_klippy_shutdown, reloading Moonraker printer objects");
            return await this.setupSocketSession();
        }
        if (eventName === "notify_status_update") {
            if (!event.params) {
                this.logger.error("Received 'notify_status_update' but service indicators params were undefined");
                return;
            }
            const [data, eventtime] = event.params;
            const subState = Object.keys(data)[0];
            if (Object.keys(this.printerObjects.status).includes(subState)) {
                this.printerObjects.status = _lodash.default.merge(this.printerObjects.status, data);
                this.printerObjects.eventtime = eventtime;
                await this.emitCurrentEvent(this.printerObjects);
            } else {
                this.logger.warn(`Substate ${subState} unknown`);
            }
            return;
        }
        await this.emitEvent(eventName, payload);
    }
    async afterClosed(event) {
        this.setSocketState("closed");
        delete this.socket;
        await this.emitEvent(_octoprintwebsocketadapter.WsMessage.WS_CLOSED, "connection closed");
    }
    async onError(error) {
        this.setSocketState("error");
        await this.emitEvent(_octoprintwebsocketadapter.WsMessage.WS_ERROR, error?.length ? error : "connection error");
    }
    async updateCurrentStateSafely() {
        try {
            const query = this.subscriptionObjects;
            const objects = await this.moonrakerClient.getPrinterObjectsQuery(this.login, query);
            this.printerObjects = objects.data.result;
            this.setApiState(_apistatetype.API_STATE.responding);
            return await this.emitCurrentEvent(this.printerObjects);
        } catch (e) {
            const castError = e;
            if (castError.isAxiosError) {
                if (castError?.response?.status == 503) {
                    this.printerObjects.status = null;
                    this.printerObjects.eventtime = Date.now();
                    return await this.emitCurrentEvent(this.printerObjects);
                }
                this.logger.error("Could not update Moonraker printer objects due to a request error");
                this.setApiState(_apistatetype.API_STATE.noResponse);
                return;
            }
            this.logger.error(`Could not update Moonraker current due to an unknown error`);
            this.setApiState(_apistatetype.API_STATE.noResponse);
        }
    }
    async emitCurrentEvent(printerObject) {
        const originalKlipperObjects = printerObject.status;
        const flags = {
            operational: false,
            printing: false,
            cancelling: false,
            pausing: false,
            paused: false,
            resuming: false,
            finishing: false,
            closedOrError: false,
            error: false,
            ready: false,
            sdReady: false
        };
        let filename = "";
        let printTime = null;
        let stateText = "Unset";
        let error = "";
        let completion = null;
        if (originalKlipperObjects != null) {
            stateText = originalKlipperObjects.display_status?.message;
            if (originalKlipperObjects.print_stats?.state?.length) {
                const systemState = originalKlipperObjects.webhooks;
                const printState = originalKlipperObjects.print_stats.state;
                const idleState = originalKlipperObjects.idle_timeout?.state;
                filename = originalKlipperObjects.print_stats.filename;
                printTime = originalKlipperObjects.print_stats.print_duration;
                flags.operational = systemState.state === "ready";
                if (flags.operational) {
                    flags.printing = printState === "printing";
                    flags.paused = printState === "paused";
                    flags.ready = printState === "standby" && idleState !== "Printing";
                    flags.sdReady = true;
                } else {
                    flags.error = true;
                    stateText = "Klipper reports: " + (systemState.state ?? "unknown")?.toUpperCase();
                }
            }
            completion = (originalKlipperObjects.display_status?.progress ?? 0) * 100.0;
        }
        const currentMessage = {
            progress: {
                printTime,
                completion
            },
            state: {
                text: stateText,
                error,
                flags
            },
            job: {
                file: {
                    name: filename,
                    path: filename
                }
            }
        };
        await this.emitEvent("notify_status_update", originalKlipperObjects);
        await this.emitEvent("current", currentMessage);
    }
    async emitEvent(event, payload) {
        if (!this.eventEmittingAllowed) {
            return;
        }
        await this.eventEmitter2.emitAsync((0, _moonrakerconstants.moonrakerEvent)(event), {
            event,
            payload,
            printerId: this.printerId,
            printerType: _printerapiinterface.MoonrakerType
        });
    }
    setSocketState(state) {
        this.socketState = state;
        this.stateUpdated = true;
        this.stateUpdateTimestamp = Date.now();
        if (this._debugMode) {
            this.logger.log(`${this.printerId} Socket state updated to: ` + state);
        }
        this.emitEventSync(_octoprintwebsocketadapter.WsMessage.WS_STATE_UPDATED, state);
    }
    setApiState(state) {
        if (state === _apistatetype.API_STATE.globalKey) {
            throw new Error("GlobalKey is an invalid WS state for Moonraker");
        }
        this.apiState = state;
        this.apiStateUpdated = true;
        this.apiStateUpdateTimestamp = Date.now();
        if (this._debugMode) {
            this.logger.log(`${this.printerId} API state updated to: ` + state);
        }
        this.emitEventSync(_octoprintwebsocketadapter.WsMessage.API_STATE_UPDATED, state);
    }
}

//# sourceMappingURL=moonraker-websocket.adapter.js.map