"use strict";
Object.defineProperty(exports, "__esModule", {
    value: true
});
const _ftpsrv = /*#__PURE__*/ _interop_require_default(require("ftp-srv"));
const _mqtt = /*#__PURE__*/ _interop_require_default(require("mqtt"));
const _nodepath = /*#__PURE__*/ _interop_require_default(require("node:path"));
const _nodefs = /*#__PURE__*/ _interop_require_default(require("node:fs"));
const _nodeos = /*#__PURE__*/ _interop_require_default(require("node:os"));
const _selfsigned = /*#__PURE__*/ _interop_require_default(require("selfsigned"));
function _interop_require_default(obj) {
    return obj && obj.__esModule ? obj : {
        default: obj
    };
}
const DEFAULT_PORT = 990;
const DEFAULT_MQTT_PORT = 8883;
const DEFAULT_SERIAL = "01P00A000000001";
const DEFAULT_ACCESS_CODE = "12345678";
const MESSAGE_INTERVAL = 1000;
const DEFAULT_USERNAME = "bblp";
const port = process.argv[2] ? Number.parseInt(process.argv[2]) : DEFAULT_PORT;
const mqttPort = process.argv[3] ? Number.parseInt(process.argv[3]) : DEFAULT_MQTT_PORT;
const serial = process.argv[4] || DEFAULT_SERIAL;
const accessCode = process.argv[5] || DEFAULT_ACCESS_CODE;
console.log(`[BAMBU MOCK] Starting Bambu Lab mock server`);
console.log(`[BAMBU MOCK] Configuration:`);
console.log(`[BAMBU MOCK]   FTP Port: ${port}`);
console.log(`[BAMBU MOCK]   MQTT Broker expected at: mqtts://localhost:${mqttPort}`);
console.log(`[BAMBU MOCK]   Serial: ${serial}`);
console.log(`[BAMBU MOCK]   Access Code: ${accessCode}`);
console.log(`[BAMBU MOCK]   Username: bblp`);
const ftpDir = _nodepath.default.join(_nodeos.default.tmpdir(), "bambu-mock-ftp", serial);
if (!_nodefs.default.existsSync(ftpDir)) {
    console.log(`[BAMBU MOCK] Creating FTP directory: ${ftpDir}`);
    _nodefs.default.mkdirSync(ftpDir, {
        recursive: true
    });
}
async function generateSelfSignedCert() {
    console.log(`[BAMBU MOCK] Generating self-signed certificate for TLS...`);
    const attrs = [
        {
            name: "commonName",
            value: "BambuLab Mock Printer"
        },
        {
            name: "countryName",
            value: "US"
        },
        {
            name: "organizationName",
            value: "Bambu Lab Mock"
        }
    ];
    const options = {
        days: 365,
        algorithm: "sha256",
        keySize: 2048
    };
    const pems = await _selfsigned.default.generate(attrs, options);
    console.log(`[BAMBU MOCK] Self-signed certificate generated successfully`);
    return {
        key: pems.private,
        cert: pems.cert,
        minVersion: "TLSv1.2",
        ciphers: "HIGH:!aNULL:!MD5"
    };
}
let isPrinting = false;
let isFinished = false;
let currentPrintFile = "";
let finishedFileName = "";
let printProgress = 0;
let isPaused = false;
let nozzleTemp = 25;
let bedTemp = 25;
let printStartTime = 0;
const PRINT_DURATION = 20;
let hasReceivedPushall = false;
let publishInterval = null;
(async ()=>{
    const tlsCerts = await generateSelfSignedCert();
    const ftpServer = new _ftpsrv.default({
        url: `ftps://0.0.0.0:${port}`,
        pasv_url: "127.0.0.1",
        pasv_min: 1024,
        pasv_max: 1048,
        tls: tlsCerts,
        anonymous: false,
        greeting: [
            "Welcome to Bambu Lab Mock FTP Server"
        ]
    });
    ftpServer.on("login", ({ username, password }, resolve, reject)=>{
        console.log(`[BAMBU MOCK FTP] Login attempt - Username: ${username}`);
        if (username === "bblp" && password === accessCode) {
            console.log(`[BAMBU MOCK FTP] Authentication successful`);
            resolve({
                root: ftpDir
            });
        } else {
            console.log(`[BAMBU MOCK FTP] Authentication failed`);
            reject(new Error("Invalid username or password"));
        }
    });
    ftpServer.on("client-error", ({ error })=>{
        console.error(`[BAMBU MOCK FTP] Client error:`, error);
    });
    ftpServer.listen().then(()=>{
        console.log(`[BAMBU MOCK FTP] FTP server is running on port ${port} with implicit TLS`);
        console.log(`[BAMBU MOCK FTP] FTP directory: ${ftpDir}`);
    });
    const mqttClient = _mqtt.default.connect(`mqtts://localhost:${mqttPort}`, {
        clientId: `bambu_mock_${serial}_${Date.now()}`,
        username: DEFAULT_USERNAME,
        password: accessCode,
        rejectUnauthorized: false
    });
    const reportTopic = `device/${serial}/report`;
    const publishState = (sequenceId)=>{
        if (isFinished) {
            isFinished = false;
            finishedFileName = "";
            currentPrintFile = "";
            printProgress = 0;
        } else if (isPrinting && !isPaused) {
            const elapsedSeconds = (Date.now() - printStartTime) / 1000;
            printProgress = Math.min(elapsedSeconds / PRINT_DURATION * 100, 100);
            if (printProgress < 10) {
                nozzleTemp = Math.min(nozzleTemp + 10, 220);
                bedTemp = Math.min(bedTemp + 5, 60);
            } else {
                nozzleTemp = 220;
                bedTemp = 60;
            }
            if (printProgress >= 100) {
                isFinished = true;
                finishedFileName = currentPrintFile;
                isPrinting = false;
                printProgress = 100;
                console.log(`[BAMBU MOCK MQTT] Print completed: ${currentPrintFile}`);
            }
        }
        if (!isPrinting && !isFinished && nozzleTemp > 25) {
            nozzleTemp = Math.max(nozzleTemp - 2, 25);
            bedTemp = Math.max(bedTemp - 1, 25);
        }
        let gcodeState = "IDLE";
        if (isFinished) gcodeState = "FINISHED";
        else if (isPrinting && isPaused) gcodeState = "PAUSE";
        else if (isPrinting) gcodeState = "PRINTING";
        const fileName = isFinished ? finishedFileName : currentPrintFile;
        const hasJob = isPrinting || isFinished;
        const finishedLabel = isFinished ? "finished" : "printing";
        const printingLabel = isPaused ? "paused" : finishedLabel;
        const progressOrFinished = isFinished ? 100 : printProgress;
        const state = {
            print: {
                nozzle_temper: Math.round(nozzleTemp),
                nozzle_target_temper: isPrinting ? 220 : 0,
                bed_temper: Math.round(bedTemp),
                bed_target_temper: isPrinting ? 60 : 0,
                chamber_temper: 30,
                mc_percent: isFinished ? 100 : Math.round(printProgress),
                mc_remaining_time: hasJob ? Math.round(Math.max(0, (PRINT_DURATION - (Date.now() - printStartTime) / 1000) / 60)) : 0,
                mc_print_stage: hasJob ? printingLabel : "idle",
                gcode_state: gcodeState,
                gcode_file: fileName || "",
                wifi_signal: "-45dBm",
                layer_num: hasJob ? Math.floor(progressOrFinished / 2) : 0,
                total_layer_num: hasJob ? 50 : 0,
                subtask_name: fileName || "",
                heatbreak_fan_speed: isPrinting ? "5000" : "0",
                cooling_fan_speed: isPrinting ? "8000" : "0",
                big_fan1_speed: isPrinting ? "3000" : "0",
                big_fan2_speed: isPrinting ? "3000" : "0",
                spd_lvl: 2,
                spd_mag: 100,
                print_error: 0,
                lifecycle: "product",
                command: "push_status",
                msg: 0,
                sequence_id: sequenceId ? String(Date.now()) : String(sequenceId)
            }
        };
        mqttClient.publish(reportTopic, JSON.stringify(state), {
            qos: 0
        }, (err)=>{
            if (err) {
                console.error(`[BAMBU MOCK MQTT] Failed to publish state:`, err);
            }
        });
    };
    mqttClient.on("connect", ()=>{
        console.log(`[BAMBU MOCK MQTT] Connected to MQTT broker at localhost:${mqttPort}`);
        console.log(`[BAMBU MOCK MQTT] Publishing to topic: device/${serial}/report`);
        mqttClient.subscribe(reportTopic, (err)=>{
            if (err) {
                console.error(`[BAMBU MOCK MQTT] Failed to subscribe to ${reportTopic}:`, err);
            } else {
                console.log(`[BAMBU MOCK MQTT] Subscribed to topic: ${reportTopic}`);
            }
        });
        console.log(`[BAMBU MOCK MQTT] Sending initial status update`);
        publishState();
        if (!hasReceivedPushall) {
            console.log(`[BAMBU MOCK MQTT] Waiting for pushall command to start periodic updates...`);
        }
    });
    mqttClient.on("message", (topic, message)=>{
        try {
            const payload = JSON.parse(message.toString());
            if (payload.print?.command === "push_status") {
                return;
            }
            console.log(`[BAMBU MOCK MQTT] Received command on ${topic}:`, JSON.stringify(payload));
            if (payload.pushing?.command === "pushall") {
                const sequenceId = payload.pushing.sequence_id;
                console.log(`[BAMBU MOCK MQTT] Received pushall command with sequence_id: ${sequenceId}`);
                if (hasReceivedPushall) {
                    publishState(sequenceId);
                } else {
                    hasReceivedPushall = true;
                    console.log(`[BAMBU MOCK MQTT] Starting periodic state publishing every ${MESSAGE_INTERVAL}ms`);
                    publishState(sequenceId);
                    publishInterval = setInterval(publishState, MESSAGE_INTERVAL);
                }
                return;
            }
            if (payload.print?.command) {
                const command = payload.print.command;
                const sequenceId = payload.print.sequence_id;
                console.log(`[BAMBU MOCK MQTT] Processing command: ${command} with sequence_id: ${sequenceId}`);
                if (command === "project_file" || command === "start") {
                    const filename = payload.print.param || payload.print.subtask_name || "unknown.gcode";
                    if (filename.endsWith(".gcode") || filename.endsWith(".3mf")) {
                        isPrinting = true;
                        isPaused = false;
                        printStartTime = Date.now();
                        printProgress = 0;
                        currentPrintFile = filename;
                        console.log(`[BAMBU MOCK MQTT] Starting print: ${filename} (20 second duration)`);
                    } else {
                        console.log(`[BAMBU MOCK MQTT] Rejected print - invalid file extension: ${filename}`);
                    }
                } else if (command === "pause") {
                    if (isPrinting) {
                        isPaused = true;
                        console.log(`[BAMBU MOCK MQTT] Pausing print`);
                    }
                } else if (command === "resume") {
                    if (isPrinting && isPaused) {
                        isPaused = false;
                        const pausedProgress = printProgress;
                        printStartTime = Date.now() - pausedProgress / 100 * PRINT_DURATION * 1000;
                        console.log(`[BAMBU MOCK MQTT] Resuming print from ${Math.round(pausedProgress)}%`);
                    }
                } else if (command === "stop") {
                    if (isPrinting) {
                        const stoppedFile = currentPrintFile;
                        isPrinting = false;
                        isPaused = false;
                        printProgress = 0;
                        console.log(`[BAMBU MOCK MQTT] Stopping print: ${stoppedFile}`);
                        setTimeout(()=>{
                            if (!isPrinting) {
                                currentPrintFile = "";
                            }
                        }, MESSAGE_INTERVAL * 2);
                    }
                }
                console.log(`[BAMBU MOCK MQTT] Sending response with sequence_id: ${sequenceId}`);
                publishState(sequenceId);
            }
        } catch (error) {
            console.error(`[BAMBU MOCK MQTT] Error processing message:`, error);
        }
    });
    mqttClient.on("error", (error)=>{
        console.error(`[BAMBU MOCK MQTT] MQTT error:`, error);
    });
    mqttClient.on("disconnect", ()=>{
        console.log(`[BAMBU MOCK MQTT] Disconnected from MQTT broker`);
    });
    process.on("SIGINT", async ()=>{
        console.log("\n[BAMBU MOCK] Shutting down gracefully...");
        if (publishInterval) {
            clearInterval(publishInterval);
            publishInterval = null;
        }
        if (mqttClient.connected) {
            console.log("[BAMBU MOCK MQTT] Disconnecting MQTT client...");
            await mqttClient.endAsync();
        }
        console.log("[BAMBU MOCK FTP] Closing FTP server...");
        await ftpServer.close();
        console.log("[BAMBU MOCK] Cleanup complete. Exiting.");
        process.exit(0);
    });
    process.on("SIGTERM", async ()=>{
        console.log("\n[BAMBU MOCK] Received SIGTERM. Shutting down...");
        if (publishInterval) {
            clearInterval(publishInterval);
            publishInterval = null;
        }
        if (mqttClient.connected) {
            await mqttClient.endAsync();
        }
        await ftpServer.close();
        process.exit(0);
    });
    console.log(`[BAMBU MOCK] Mock server is running. Press Ctrl+C to stop.`);
})().catch((error)=>{
    console.error("[BAMBU MOCK] Fatal error during startup:", error);
    process.exit(1);
});

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