"use strict";
Object.defineProperty(exports, "__esModule", {
    value: true
});
const _express = /*#__PURE__*/ _interop_require_default(require("express"));
const _multer = /*#__PURE__*/ _interop_require_default(require("multer"));
const _nodefs = /*#__PURE__*/ _interop_require_default(require("node:fs"));
const _nodepath = /*#__PURE__*/ _interop_require_default(require("node:path"));
const _ws = require("ws");
const _nodehttp = /*#__PURE__*/ _interop_require_default(require("node:http"));
const _zod = require("zod");
const _nodeconsole = /*#__PURE__*/ _interop_require_wildcard(require("node:console"));
const _apimessages = require("./utils/api-messages");
function _interop_require_default(obj) {
    return obj && obj.__esModule ? obj : {
        default: obj
    };
}
function _getRequireWildcardCache(nodeInterop) {
    if (typeof WeakMap !== "function") return null;
    var cacheBabelInterop = new WeakMap();
    var cacheNodeInterop = new WeakMap();
    return (_getRequireWildcardCache = function(nodeInterop) {
        return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
    })(nodeInterop);
}
function _interop_require_wildcard(obj, nodeInterop) {
    if (!nodeInterop && obj && obj.__esModule) {
        return obj;
    }
    if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
        return {
            default: obj
        };
    }
    var cache = _getRequireWildcardCache(nodeInterop);
    if (cache && cache.has(obj)) {
        return cache.get(obj);
    }
    var newObj = {
        __proto__: null
    };
    var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
    for(var key in obj){
        if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
            var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
            if (desc && (desc.get || desc.set)) {
                Object.defineProperty(newObj, key, desc);
            } else {
                newObj[key] = obj[key];
            }
        }
    }
    newObj.default = obj;
    if (cache) {
        cache.set(obj, newObj);
    }
    return newObj;
}
let isPrinting = false;
let isPaused = false;
let isFinished = false;
let currentPrintFile = "";
let printProgress = 0;
let printStartTime = 0;
const PRINT_DURATION = 20;
function getCurrentMessage() {
    updatePrintProgress();
    const elapsedSeconds = isPrinting ? (Date.now() - printStartTime) / 1000 : 0;
    const remainingSeconds = isPrinting ? Math.max(0, PRINT_DURATION - elapsedSeconds) : null;
    let stateText = "Operational";
    if (isPrinting && isPaused) stateText = "Paused";
    else if (isPrinting) stateText = "Printing";
    const fileName = isFinished ? finishedFileName : currentPrintFile || null;
    const hasFile = isPrinting || isFinished;
    return {
        current: {
            state: {
                text: stateText,
                flags: {
                    operational: true,
                    printing: isPrinting && !isPaused,
                    cancelling: false,
                    pausing: false,
                    resuming: false,
                    finishing: false,
                    closedOrError: false,
                    error: false,
                    paused: isPaused,
                    ready: !isPrinting && !isFinished,
                    sdReady: true,
                    finished: isFinished
                },
                error: ""
            },
            job: {
                file: {
                    name: fileName,
                    path: fileName,
                    display: fileName,
                    origin: hasFile ? "local" : null,
                    size: hasFile ? 1024000 : null,
                    date: hasFile ? printStartTime / 1000 : null
                },
                estimatedPrintTime: hasFile ? PRINT_DURATION : null,
                averagePrintTime: null,
                lastPrintTime: null,
                filament: hasFile ? {
                    tool0: {
                        length: 1000,
                        volume: 2.4
                    }
                } : null,
                user: null
            },
            currentZ: isPrinting ? Math.floor(printProgress / 5) : null,
            progress: {
                completion: isFinished ? 100 : isPrinting ? printProgress : null,
                filepos: hasFile ? Math.floor((isFinished ? 100 : printProgress) / 100 * 1024000) : null,
                printTime: isFinished ? PRINT_DURATION : isPrinting ? Math.floor(elapsedSeconds) : null,
                printTimeLeft: isFinished ? 0 : remainingSeconds !== null ? Math.floor(remainingSeconds) : null,
                printTimeLeftOrigin: hasFile ? "estimate" : null
            },
            offsets: {},
            resends: {
                count: 0,
                transmitted: 8,
                ratio: 0
            },
            serverTime: Date.now() / 1000,
            temps: [],
            busyFiles: [],
            logs: [],
            messages: []
        }
    };
}
let finishedFileName = "";
function updatePrintProgress() {
    if (isFinished) {
        isFinished = false;
        finishedFileName = "";
        currentPrintFile = "";
        printProgress = 0;
        return;
    }
    if (isPrinting && !isPaused) {
        const elapsedSeconds = (Date.now() - printStartTime) / 1000;
        printProgress = Math.min(elapsedSeconds / PRINT_DURATION * 100, 100);
        if (printProgress >= 100) {
            isFinished = true;
            finishedFileName = currentPrintFile;
            isPrinting = false;
            printProgress = 100;
            _nodeconsole.log(`[PORT] Print completed: ${currentPrintFile}`);
        }
    }
}
function getJobResponse() {
    updatePrintProgress();
    const fileName = isFinished ? finishedFileName : currentPrintFile;
    const hasJob = isPrinting || isFinished;
    if (!hasJob) {
        return {
            job: {
                file: {
                    name: null,
                    origin: null,
                    size: null,
                    date: null
                },
                estimatedPrintTime: null,
                filament: null
            },
            progress: {
                completion: null,
                filepos: null,
                printTime: null,
                printTimeLeft: null
            },
            state: "Operational"
        };
    }
    const elapsedSeconds = (Date.now() - printStartTime) / 1000;
    const remainingSeconds = Math.max(0, PRINT_DURATION - elapsedSeconds);
    let state = "Printing";
    if (isFinished) state = "Operational";
    else if (isPaused) state = "Paused";
    return {
        job: {
            file: {
                name: fileName,
                origin: "local",
                size: 1024000,
                date: printStartTime / 1000
            },
            estimatedPrintTime: PRINT_DURATION,
            filament: {
                tool0: {
                    length: 1000,
                    volume: 2.4
                }
            }
        },
        progress: {
            completion: isFinished ? 100 : printProgress,
            filepos: Math.floor((isFinished ? 100 : printProgress) / 100 * 1024000),
            printTime: isFinished ? PRINT_DURATION : Math.floor(elapsedSeconds),
            printTimeLeft: isFinished ? 0 : Math.floor(remainingSeconds)
        },
        state
    };
}
const port = process.argv[2] ? Number.parseInt(process.argv[2]) : 1234;
const uploadsDir = _nodepath.default.join(__dirname, "uploads", `server-${port.toString()}`);
const WS_MESSAGE_INTERVAL = 1000;
if (!_nodefs.default.existsSync(uploadsDir)) {
    _nodeconsole.log(`[PORT ${port}] Creating uploads folder ${uploadsDir}`);
    _nodefs.default.mkdirSync(uploadsDir, {
        recursive: true
    });
}
cleanupUploads();
const upload = (0, _multer.default)({
    dest: uploadsDir
});
const app = (0, _express.default)();
const server = _nodehttp.default.createServer(app);
const wss = new _ws.Server({
    server
});
const clients = new Map();
const AuthSchema = _zod.z.object({
    command: _zod.z.literal("auth"),
    user: _zod.z.literal("admin"),
    token: _zod.z.string().regex(/^[a-zA-Z0-9]{32}$/)
});
wss.on("connection", (ws)=>{
    const clientId = Date.now().toString();
    _nodeconsole.log(`[PORT ${port}] New WebSocket connection established`);
    let authenticated = false;
    let messageInterval = null;
    ws.on("message", async (message)=>{
        try {
            const msgString = message.toString();
            if (msgString.includes("throttle")) {
                _nodeconsole.log(`Throttle message received ${msgString}`);
                return;
            }
            const json = JSON.parse(msgString);
            if (authenticated) {
                _nodeconsole.log(`[PORT ${port}] Received message from authenticated client`);
                return;
            }
            if (!json) {
                _nodeconsole.log(`[PORT ${port}] Invalid message JSON format`);
                ws.close();
                return;
            }
            try {
                const parts = json.auth.split(":");
                AuthSchema.parse({
                    command: "auth",
                    user: parts[0],
                    token: parts[1]
                });
                _nodeconsole.log(`[PORT ${port}] Authentication successful for admin`);
                authenticated = true;
                clients.set(clientId, {
                    ws,
                    authenticated
                });
                setTimeout(async ()=>{
                    try {
                        ws.send(JSON.stringify(getCurrentMessage()));
                    } catch (fileError) {
                        _nodeconsole.error(`[PORT ${port}] Error reading message file:`, fileError);
                        ws.send(JSON.stringify({
                            error: "Failed to read message content"
                        }));
                    }
                }, 500);
                messageInterval = setupMessageInterval(ws, clientId, WS_MESSAGE_INTERVAL);
            } catch (validationError) {
                _nodeconsole.log(`[PORT ${port}] Authentication failed: Invalid token format ${JSON.stringify(json)} ${validationError}`);
                ws.close();
            }
        } catch (error) {
            _nodeconsole.error(`[PORT ${port}] Error processing message:`, error);
            ws.close();
        }
    });
    ws.on("close", ()=>{
        _nodeconsole.log(`[PORT ${port}] WebSocket connection closed ${clientId}`);
        if (messageInterval) {
            clearInterval(messageInterval);
            messageInterval = null;
        }
        clients.delete(clientId);
    });
    const setupMessageInterval = (ws, clientId, baseInterval)=>{
        if (messageInterval) {
            clearInterval(messageInterval);
            messageInterval = null;
        }
        const getRandomizedInterval = (baseMs)=>{
            const variationFactor = 0.85 + Math.random() * 0.3;
            return Math.floor(baseMs * variationFactor);
        };
        const sendPeriodicMessage = ()=>{
            try {
                if (ws.readyState === ws.OPEN) {
                    ws.send(JSON.stringify(getCurrentMessage()));
                    _nodeconsole.log(`[PORT ${port}] Periodic message sent to client (ID: ${clientId})`);
                    messageInterval = setTimeout(sendPeriodicMessage, getRandomizedInterval(baseInterval));
                } else {
                    _nodeconsole.log(`[PORT ${port}] Stopped periodic messages for client (ID: ${clientId})`);
                    messageInterval = null;
                }
            } catch (error) {
                _nodeconsole.error(`[PORT ${port}] Error sending periodic message:`, error);
                messageInterval = null;
            }
        };
        messageInterval = setTimeout(sendPeriodicMessage, getRandomizedInterval(baseInterval));
        return messageInterval;
    };
});
app.get("/api/version", async (req, res)=>{
    res.send({
        server: "1",
        api: "2",
        text: "3"
    });
});
app.get("/api/currentuser", async (req, res)=>{
    res.send({
        name: "admin",
        permissions: [],
        groups: []
    });
});
app.get("/api/printer", async (req, res)=>{
    _nodeconsole.log(`[PORT ${port}] ${req.method.toUpperCase()} ${req.url} request`);
    res.status(200).json(_apimessages.printerHistorySuccessResponse);
});
app.get("/api/connection", async (req, res)=>{
    _nodeconsole.log(`[PORT ${port}] ${req.method.toUpperCase()} ${req.url} request`);
    res.status(200).json(_apimessages.connectionSuccessResponse);
});
app.get("/api/job", async (req, res)=>{
    _nodeconsole.log(`[PORT ${port}] ${req.method.toUpperCase()} ${req.url} request`);
    res.status(200).json(getJobResponse());
});
app.post("/api/job", _express.default.json(), async (req, res)=>{
    const { command, action } = req.body;
    _nodeconsole.log(`[PORT ${port}] POST /api/job - command: ${command}, action: ${action}`);
    if (command === "cancel") {
        if (isPrinting) {
            isPrinting = false;
            isPaused = false;
            printProgress = 0;
            currentPrintFile = "";
            _nodeconsole.log(`[PORT ${port}] Print cancelled`);
        }
        return res.status(204).send();
    }
    if (command === "pause") {
        if (action === "pause" && isPrinting && !isPaused) {
            isPaused = true;
            _nodeconsole.log(`[PORT ${port}] Print paused at ${Math.round(printProgress)}%`);
        } else if (action === "resume" && isPrinting && isPaused) {
            isPaused = false;
            const pausedProgress = printProgress;
            printStartTime = Date.now() - pausedProgress / 100 * PRINT_DURATION * 1000;
            _nodeconsole.log(`[PORT ${port}] Print resumed from ${Math.round(pausedProgress)}%`);
        }
        return res.status(204).send();
    }
    res.status(400).json({
        error: "Unknown command"
    });
});
app.get("/api/files/local", async (req, res)=>{
    _nodeconsole.log(`[PORT ${port}] ${req.method.toUpperCase()} ${req.url} request`);
    res.status(200).json(_apimessages.filesSuccessResponse);
});
app.post("/api/login", async (req, res)=>{
    res.send({
        _is_external_client: true,
        _login_mechanism: "apikey",
        session: "123123abc123123abc123123abc123ab"
    });
});
app.post("/api/files/local/:path(*)", _express.default.json(), (req, res)=>{
    const filePath = req.params.path;
    const { command, print } = req.body;
    _nodeconsole.log(`[PORT ${port}] POST /api/files/local/${filePath} - command: ${command}, print: ${print}`);
    if (command === "select") {
        if (!filePath.endsWith(".gcode") && !filePath.endsWith(".bgcode") && !filePath.endsWith(".3mf")) {
            _nodeconsole.log(`[PORT ${port}] Rejected - invalid file extension: ${filePath}`);
            return res.status(400).json({
                error: "Invalid file extension. Only .gcode, .bgcode, and .3mf files are supported"
            });
        }
        currentPrintFile = filePath;
        _nodeconsole.log(`[PORT ${port}] File selected: ${filePath}`);
        if (print === true) {
            isPrinting = true;
            isPaused = false;
            printStartTime = Date.now();
            printProgress = 0;
            _nodeconsole.log(`[PORT ${port}] Starting print: ${filePath} (${PRINT_DURATION} second duration)`);
        }
        return res.status(204).send();
    }
    if (command === "move") {
        _nodeconsole.log(`[PORT ${port}] Move command received for: ${filePath}`);
        return res.status(204).send();
    }
    res.status(400).json({
        error: "Unknown command"
    });
});
app.post("/api/files/local", upload.single("file"), (req, res)=>{
    const { print } = req.body;
    const file = req.file;
    if (!file) {
        return res.status(400).json({
            error: "Missing file"
        });
    }
    _nodeconsole.log(`[PORT ${port}] Received file:`, file.originalname);
    _nodeconsole.log(`[PORT ${port}] File size:`, file.size);
    _nodeconsole.log(`[PORT ${port}] MIME type:`, file.mimetype);
    _nodeconsole.log(`[PORT ${port}] print:`, print, `\n-----`);
    if (print === "true") {
        currentPrintFile = file.originalname;
        isPrinting = true;
        isPaused = false;
        printStartTime = Date.now();
        printProgress = 0;
        _nodeconsole.log(`[PORT ${port}] Starting print: ${file.originalname} (${PRINT_DURATION} second duration)`);
    }
    res.json({
        done: true,
        files: {
            local: {
                name: file.originalname,
                origin: "local",
                refs: {
                    resource: `/api/files/local/${file.originalname}`
                }
            }
        }
    });
});
app.use((req, res)=>{
    _nodeconsole.log(`[PORT ${port}] ${req.method.toUpperCase()} ${req.url} Not found`);
    res.status(404).json({
        error: "Not Found"
    });
});
server.listen(port, ()=>{
    _nodeconsole.log(`[PORT ${port}] Server is running on http://localhost:${port}`);
    _nodeconsole.log(`[PORT ${port}] WebSocket server is available on ws://localhost:${port}`);
});
process.on("SIGINT", ()=>{
    _nodeconsole.log("\n[PORT ${port}] Received SIGINT signal (Ctrl+C). Shutting down gracefully...");
    cleanupUploads();
    server.close(()=>{
        _nodeconsole.log("[PORT ${port}] Server closed");
        process.exit(0);
    });
});
process.on("SIGTERM", ()=>{
    _nodeconsole.log("\n[PORT ${port}] Received SIGTERM signal. Shutting down gracefully...");
    cleanupUploads();
    server.close(()=>{
        _nodeconsole.log("[PORT ${port}] Server closed");
        process.exit(0);
    });
});
function cleanupUploads() {
    try {
        _nodeconsole.log(`[PORT ${port}] Cleaning up uploads folder...`);
        const files = _nodefs.default.readdirSync(uploadsDir);
        for (const file of files){
            const filePath = _nodepath.default.join(uploadsDir, file);
            _nodefs.default.unlinkSync(filePath);
            _nodeconsole.log(`[PORT ${port}] Deleted: ${filePath}`);
        }
        _nodeconsole.log(`[PORT ${port}] Uploads folder cleanup complete`);
    } catch (error) {
        _nodeconsole.error(`[PORT ${port}] Error cleaning up uploads folder:`, error);
    }
}

//# sourceMappingURL=mock-octoprint.server.js.map