"use strict";
Object.defineProperty(exports, "__esModule", {
    value: true
});
Object.defineProperty(exports, "PrinterEventsCache", {
    enumerable: true,
    get: function() {
        return PrinterEventsCache;
    }
});
const _keydiffcache = require("../utils/cache/key-diff.cache");
const _eventconstants = require("../constants/event.constants");
const _octoprinteventdto = require("../services/octoprint/dto/octoprint-event.dto");
const _octoprintwebsocketadapter = require("../services/octoprint/octoprint-websocket.adapter");
const _moonrakerconstants = require("../services/moonraker/constants/moonraker.constants");
const _prusalinkconstants = require("../services/prusa-link/constants/prusalink.constants");
const _bambumqttadapter = require("../services/bambu/bambu-mqtt.adapter");
class PrinterEventsCache extends _keydiffcache.KeyDiffCache {
    eventEmitter2;
    printJobService;
    printerCache;
    printerThumbnailCache;
    logger;
    constructor(eventEmitter2, loggerFactory, printJobService, printerCache, printerThumbnailCache){
        super(), this.eventEmitter2 = eventEmitter2, this.printJobService = printJobService, this.printerCache = printerCache, this.printerThumbnailCache = printerThumbnailCache;
        this.logger = loggerFactory(PrinterEventsCache.name);
        this.subscribeToEvents();
    }
    async deletePrinterSocketEvents(id) {
        await this.deleteKeyValue(id, true);
    }
    async getPrinterSocketEvents(id) {
        return this.keyValueStore.get(id);
    }
    async getOrCreateEvents(printerId) {
        let ref = await this.getValue(printerId);
        if (!ref) {
            ref = {
                connected: null,
                reauthRequired: null,
                notify_status_update: null,
                current: null,
                history: null,
                API_STATE_UPDATED: null,
                WS_CLOSED: null,
                WS_ERROR: null,
                WS_OPENED: null,
                WS_STATE_UPDATED: null
            };
            await this.setKeyValue(printerId, ref);
        }
        return ref;
    }
    async setEvent(printerId, label, payload) {
        const ref = await this.getOrCreateEvents(printerId);
        ref[label] = {
            payload,
            receivedAt: Date.now()
        };
        await this.setKeyValue(printerId, ref);
    }
    async setEventPartial(printerId, label, payload, keysToUpdate) {
        const ref = await this.getOrCreateEvents(printerId);
        if (!ref[label]) {
            ref[label] = {
                payload: {},
                receivedAt: Date.now()
            };
        }
        for (const key of keysToUpdate){
            ref[label].payload[key] = payload[key];
        }
        ref[label].receivedAt = Date.now();
        await this.setKeyValue(printerId, ref);
    }
    async handlePrintersDeleted(event) {
        await this.deleteKeysBatch(event.printerIds);
    }
    subscribeToEvents() {
        this.eventEmitter2.on((0, _octoprintwebsocketadapter.octoPrintEvent)("*"), (e)=>this.onOctoPrintSocketMessage(e));
        this.eventEmitter2.on((0, _moonrakerconstants.moonrakerEvent)("*"), (e)=>this.onMoonrakerSocketMessage(e));
        this.eventEmitter2.on((0, _prusalinkconstants.prusaLinkEvent)("*"), (e)=>this.onPrusaLinkPollMessage(e));
        this.eventEmitter2.on((0, _bambumqttadapter.bambuEvent)("*"), (e)=>this.onBambuSocketMessage(e));
        this.eventEmitter2.on(_eventconstants.printerEvents.printersDeleted, this.handlePrintersDeleted.bind(this));
    }
    async getPrinterName(printerId) {
        try {
            const printer = await this.printerCache.getValue(printerId);
            return printer?.name;
        } catch (error) {
            this.logger.debug(`Could not get printer name for ${printerId}: ${error}`);
            return undefined;
        }
    }
    async onOctoPrintSocketMessage(e) {
        const printerId = e.printerId;
        if (e.event === _octoprinteventdto.messages.current && e.payload) {
            const payload = e.payload;
            const keysToUpdate = [
                'state',
                'job',
                'progress',
                'currentZ',
                'offsets',
                'resends'
            ];
            if (Array.isArray(payload.temps) && payload.temps.length > 0) {
                keysToUpdate.push('temps');
            }
            await this.setEventPartial(printerId, _octoprinteventdto.messages.current, payload, keysToUpdate);
            const flags = payload?.state?.flags;
            const filePath = payload?.job?.file?.path;
            const completion = payload?.progress?.completion;
            if (flags?.printing && filePath) {
                const printerName = await this.getPrinterName(printerId);
                const job = await this.printJobService.markStarted(printerId, filePath, printerName);
                if (job) {
                    await this.printerThumbnailCache.handleJobStarted(printerId, job.id);
                }
                if (job && !job.fileStorageId && job.analysisState === "NOT_ANALYZED") {
                    this.logger.log(`Job ${job.id} has no local file - triggering download and analysis`);
                    await this.printJobService.triggerFileAnalysis(job.id);
                }
                if (job && !job.metadata?.gcodePrintTimeSeconds) {
                    const estimatedTime = payload?.job?.estimatedPrintTime;
                    const filament = payload?.job?.filament?.tool0;
                    await this.printJobService.updateJobMetadata(printerId, filePath, {
                        gcodePrintTimeSeconds: estimatedTime ? Math.round(estimatedTime) : null,
                        nozzleDiameterMm: null,
                        filamentDiameterMm: null,
                        filamentDensityGramsCm3: null,
                        filamentUsedMm: filament?.length ? Math.round(filament.length) : null,
                        filamentUsedCm3: filament?.volume ? Math.round(filament.volume * 100) / 100 : null,
                        filamentUsedGrams: null,
                        totalFilamentUsedGrams: null
                    });
                }
            }
            if (typeof completion === "number" && filePath) {
                await this.printJobService.markProgress(printerId, filePath, completion);
            }
            if ((flags?.finishing || flags?.error || flags?.cancelling) && filePath) {
                if (flags?.finishing) {
                    const job = await this.printJobService.markFinished(printerId, filePath);
                    if (job) {
                        await this.printerThumbnailCache.handleJobCompleted(printerId, job.id);
                    }
                } else if (flags?.cancelling) {
                    await this.printJobService.markFailed(printerId, filePath, "Cancelled");
                } else {
                    await this.printJobService.markFailed(printerId, filePath, "Error");
                }
            }
        }
    }
    async onMoonrakerSocketMessage(e) {
        const printerId = e.printerId;
        const eventType = e.event;
        if ([
            _octoprinteventdto.messages.notify_status_update,
            _octoprinteventdto.messages.current
        ].includes(eventType)) {
            await this.setEvent(printerId, eventType, e.payload);
            const payload = e.payload;
            const status = payload?.status ?? payload?.result ?? {};
            const filename = status?.print_stats?.filename;
            const progress = status?.display_status?.progress ?? status?.print_stats?.progress;
            const state = status?.print_stats?.state;
            if (state === "printing" && filename) {
                const printerName = await this.getPrinterName(printerId);
                const job = await this.printJobService.markStarted(printerId, filename, printerName);
                if (job) {
                    await this.printerThumbnailCache.handleJobStarted(printerId, job.id);
                }
                if (job && !job.fileStorageId && job.analysisState === "NOT_ANALYZED") {
                    this.logger.log(`Job ${job.id} has no local file - triggering download and analysis`);
                    await this.printJobService.triggerFileAnalysis(job.id);
                }
            }
            if (typeof progress === "number" && filename) {
                await this.printJobService.markProgress(printerId, filename, Math.round(progress * 100));
            }
            if ([
                "complete",
                "cancelled",
                "error"
            ].includes(state) && filename) {
                if (state === "complete") {
                    const job = await this.printJobService.markFinished(printerId, filename);
                    if (job) {
                        await this.printerThumbnailCache.handleJobCompleted(printerId, job.id);
                    }
                } else {
                    await this.printJobService.markFailed(printerId, filename, state);
                }
            }
        }
    }
    async onPrusaLinkPollMessage(e) {
        const printerId = e.printerId;
        if (e.event === _octoprinteventdto.messages.current) {
            await this.setEvent(printerId, _octoprinteventdto.messages.current, e.payload);
            const payload = e.payload;
            const state = payload?.state;
            const filename = payload?.job?.file?.path ?? payload?.job?.file?.display;
            const completion = payload?.progress?.completion;
            if (state === "Printing" && filename) {
                const printerName = await this.getPrinterName(printerId);
                const job = await this.printJobService.markStarted(printerId, filename, printerName);
                if (job) {
                    await this.printerThumbnailCache.handleJobStarted(printerId, job.id);
                }
                if (job && !job.fileStorageId && job.analysisState === "NOT_ANALYZED") {
                    this.logger.log(`Job ${job.id} has no local file - triggering download and analysis`);
                    await this.printJobService.triggerFileAnalysis(job.id);
                }
            }
            if (typeof completion === "number" && filename) {
                await this.printJobService.markProgress(printerId, filename, completion);
            }
            if (state === "Finished" && filename) {
                const job = await this.printJobService.markFinished(printerId, filename);
                if (job) {
                    await this.printerThumbnailCache.handleJobCompleted(printerId, job.id);
                }
            } else if ([
                "Stopped",
                "Error"
            ].includes(state) && filename) {
                await this.printJobService.markFailed(printerId, filename, state);
            }
        }
    }
    async onBambuSocketMessage(e) {
        const printerId = e.printerId;
        if (!printerId) {
            this.logger.warn("Received Bambu event without printerId", e);
            return;
        }
        if (e.event === _octoprinteventdto.messages.current) {
            await this.setEvent(printerId, _octoprinteventdto.messages.current, e.payload);
            const payload = e.payload;
            const print = payload?.print;
            const percent = print?.mc_percent;
            const filename = print?.gcode_file || print?.subtask_name;
            const stage = print?.mc_print_stage;
            const state = print?.gcode_state;
            if (state === "PRINTING" && filename) {
                const printerName = await this.getPrinterName(printerId);
                const job = await this.printJobService.markStarted(printerId, filename, printerName);
                if (job) {
                    await this.printerThumbnailCache.handleJobStarted(printerId, job.id);
                }
                if (job && !job.fileStorageId && job.analysisState === "NOT_ANALYZED") {
                    this.logger.log(`Job ${job.id} has no local file - triggering download and analysis`);
                    await this.printJobService.triggerFileAnalysis(job.id);
                }
                if (job && !job.metadata?.gcodePrintTimeSeconds) {
                    const remainingMinutes = print?.mc_remaining_time;
                    const totalLayers = print?.total_layer_num;
                    const estimatedSeconds = remainingMinutes ? remainingMinutes * 60 : null;
                    const tray = print?.ams?.tray_now ? print?.vt_tray : print?.ams?.ams?.[0]?.tray?.[0];
                    const filamentDiameter = tray?.tray_diameter ? parseFloat(tray.tray_diameter) : null;
                    await this.printJobService.updateJobMetadata(printerId, filename, {
                        gcodePrintTimeSeconds: estimatedSeconds,
                        nozzleDiameterMm: null,
                        filamentDiameterMm: filamentDiameter,
                        filamentDensityGramsCm3: null,
                        filamentUsedMm: null,
                        filamentUsedCm3: null,
                        filamentUsedGrams: null,
                        totalFilamentUsedGrams: null
                    });
                }
            }
            if (typeof percent === "number" && filename) {
                await this.printJobService.markProgress(printerId, filename, percent);
            }
            if (state === "FINISHED" && filename) {
                const job = await this.printJobService.markFinished(printerId, filename);
                if (job) {
                    await this.printerThumbnailCache.handleJobCompleted(printerId, job.id);
                }
            } else if (state === "IDLE") {
                const activeJob = await this.printJobService.getActivePrintJob(printerId);
                if (activeJob && activeJob.status === "PRINTING") {
                    this.logger.log(`Print job ${activeJob.id} transitioned to IDLE - marking as cancelled`);
                    await this.printJobService.handlePrintCancelled(printerId, "Print stopped");
                }
            } else if (state === "ERROR" && filename) {
                await this.printJobService.markFailed(printerId, filename, "Error");
            }
        }
    }
}

//# sourceMappingURL=printer-events.cache.js.map