"use strict";
Object.defineProperty(exports, "__esModule", {
    value: true
});
const _mqtt = /*#__PURE__*/ _interop_require_default(require("mqtt"));
const _nodereadline = /*#__PURE__*/ _interop_require_wildcard(require("node:readline"));
const _nodefs = /*#__PURE__*/ _interop_require_wildcard(require("node:fs"));
const _nodepath = /*#__PURE__*/ _interop_require_wildcard(require("node:path"));
require("dotenv/config");
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;
}
const host = process.argv[2] || process.env.BAMBU_HOST;
const accessCode = process.argv[3] || process.env.BAMBU_ACCESS_CODE;
const serial = process.argv[4] || process.env.BAMBU_SERIAL;
if (!host || !accessCode || !serial) {
    console.error("Missing required configuration.");
    console.error("");
    console.error("Please provide configuration via .env file:");
    console.error("  BAMBU_HOST=<printer_ip>");
    console.error("  BAMBU_ACCESS_CODE=<8_character_access_code>");
    console.error("  BAMBU_SERIAL=<printer_serial_number>");
    console.error("");
    console.error("Or via command line arguments:");
    console.error("  yarn console:bambu-mqtt-diagnostic <host> <accessCode> <serial>");
    process.exit(1);
}
const MQTT_PORT = 8883;
const MQTT_USERNAME = "bblp";
const RECONNECT_PERIOD = 5000;
const COMMAND_TIMEOUT = 10000;
let client = null;
let lastState = null;
let messageCount = 0;
let lastMessageTime = null;
let connectionStartTime = null;
let sequenceIdCounter = 10;
let isVerbose = false;
let dumpEnabled = true;
let dumpStream = null;
let dumpFilePath = null;
let dumpMessageCount = 0;
function initDumpFile() {
    const timestamp = new Date().toISOString().replaceAll(/[:.]/g, "-");
    const dumpDir = _nodepath.join(process.cwd(), "mqtt-dumps");
    if (!_nodefs.existsSync(dumpDir)) {
        _nodefs.mkdirSync(dumpDir, {
            recursive: true
        });
    }
    dumpFilePath = _nodepath.join(dumpDir, `bambu-mqtt-dump-${timestamp}.jsonl`);
    dumpStream = _nodefs.createWriteStream(dumpFilePath, {
        flags: "a"
    });
    const header = {
        _type: "session_start",
        _timestamp: new Date().toISOString(),
        host,
        serial,
        port: MQTT_PORT
    };
    dumpStream.write(JSON.stringify(header) + "\n");
    log(`MQTT dump file: ${dumpFilePath}`, "INFO");
}
function writeToDump(direction, topic, payload) {
    if (!dumpEnabled || !dumpStream) return;
    dumpMessageCount++;
    const entry = {
        _seq: dumpMessageCount,
        _timestamp: new Date().toISOString(),
        _direction: direction,
        topic,
        payload
    };
    dumpStream.write(JSON.stringify(entry) + "\n");
}
function closeDumpFile() {
    if (dumpStream) {
        const footer = {
            _type: "session_end",
            _timestamp: new Date().toISOString(),
            totalMessages: dumpMessageCount
        };
        dumpStream.write(JSON.stringify(footer) + "\n");
        dumpStream.end();
        dumpStream = null;
        log(`Dump file closed: ${dumpFilePath} (${dumpMessageCount} messages)`, "INFO");
    }
}
function log(message, level = "INFO") {
    const timestamp = new Date().toISOString();
    const prefix = `[${timestamp}] [${level}]`;
    if (level === "ERROR") {
        console.error(`${prefix} ${message}`);
    } else if (level === "DEBUG") {
        if (isVerbose) {
            console.log(`${prefix} ${message}`);
        }
    } else {
        console.log(`${prefix} ${message}`);
    }
}
function clearScreen() {
    process.stdout.write("\x1B[2J\x1B[0f");
}
function formatTemp(current, target) {
    if (current === undefined || current === null) return "N/A";
    const curr = current.toFixed(1).padStart(6);
    if (target !== undefined && target !== null && target > 0) {
        return `${curr}C -> ${target.toFixed(1)}C`;
    }
    return `${curr}C`;
}
function formatDuration(ms) {
    const seconds = Math.floor(ms / 1000);
    const minutes = Math.floor(seconds / 60);
    const hours = Math.floor(minutes / 60);
    if (hours > 0) {
        return `${hours}h ${minutes % 60}m ${seconds % 60}s`;
    }
    if (minutes > 0) {
        return `${minutes}m ${seconds % 60}s`;
    }
    return `${seconds}s`;
}
function formatTimeRemaining(minutes) {
    if (minutes === undefined || minutes === null || minutes <= 0) return "N/A";
    const hours = Math.floor(minutes / 60);
    const mins = minutes % 60;
    if (hours > 0) {
        return `${hours}h ${mins}m`;
    }
    return `${mins}m`;
}
function createProgressBar(percent, width) {
    const filled = Math.round(percent / 100 * width);
    const empty = width - filled;
    return "[" + "=".repeat(filled) + "-".repeat(empty) + "]";
}
function printDiagnostics() {
    console.log("\n==================================================================");
    console.log("                    BAMBU MQTT DIAGNOSTIC                        ");
    console.log("==================================================================");
    console.log(`  Host:           ${host}:${MQTT_PORT}`);
    console.log(`  Serial:         ${serial}`);
    console.log(`  Access Code:    ${"*".repeat(accessCode?.length || 0)}`);
    console.log(`  Topic:          device/${serial}/report`);
    console.log("------------------------------------------------------------------");
    console.log(`  Connection:     ${client?.connected ? "CONNECTED" : "DISCONNECTED"}`);
    if (connectionStartTime) {
        console.log(`  Uptime:         ${formatDuration(Date.now() - connectionStartTime.getTime())}`);
    }
    console.log(`  Messages:       ${messageCount}`);
    if (lastMessageTime) {
        console.log(`  Last Message:   ${lastMessageTime.toISOString()}`);
        console.log(`  Time Since:     ${formatDuration(Date.now() - lastMessageTime.getTime())} ago`);
    }
    console.log("------------------------------------------------------------------");
    console.log(`  Dump Enabled:   ${dumpEnabled ? "YES" : "NO"}`);
    if (dumpFilePath) {
        console.log(`  Dump File:      ${_nodepath.basename(dumpFilePath)}`);
        console.log(`  Dumped Msgs:    ${dumpMessageCount}`);
    }
    console.log("==================================================================");
}
function printState() {
    if (!lastState) {
        console.log("\n  Waiting for printer state...\n");
        return;
    }
    console.log("\n------------------------------------------------------------------");
    console.log("                        PRINTER STATE                            ");
    console.log("------------------------------------------------------------------");
    const gcodeState = lastState.gcode_state || "UNKNOWN";
    const gcodeFile = lastState.gcode_file || lastState.subtask_name || "None";
    const progress = lastState.mc_percent;
    const remaining = lastState.mc_remaining_time;
    const stage = lastState.mc_print_stage || "N/A";
    console.log(`  Status:         ${gcodeState}`);
    console.log(`  Stage:          ${stage}`);
    console.log(`  File:           ${gcodeFile.substring(0, 50)}`);
    if (progress !== undefined && progress !== null) {
        const progressBar = createProgressBar(progress, 30);
        console.log(`  Progress:       ${progressBar} ${progress.toFixed(1)}%`);
    }
    if (remaining !== undefined && remaining !== null && remaining > 0) {
        console.log(`  Remaining:      ${formatTimeRemaining(remaining)}`);
    }
    if (lastState.layer_num !== undefined && lastState.total_layer_num !== undefined) {
        console.log(`  Layer:          ${lastState.layer_num} / ${lastState.total_layer_num}`);
    }
    console.log("------------------------------------------------------------------");
    console.log("  TEMPERATURES");
    console.log(`    Nozzle:       ${formatTemp(lastState.nozzle_temper, lastState.nozzle_target_temper)}`);
    console.log(`    Bed:          ${formatTemp(lastState.bed_temper, lastState.bed_target_temper)}`);
    if (lastState.chamber_temper !== undefined) {
        console.log(`    Chamber:      ${formatTemp(lastState.chamber_temper, undefined)}`);
    }
    console.log("------------------------------------------------------------------");
    console.log("  FANS");
    console.log(`    Heatbreak:    ${lastState.heatbreak_fan_speed ?? "N/A"}`);
    console.log(`    Cooling:      ${lastState.cooling_fan_speed ?? "N/A"}`);
    console.log(`    Big Fan 1:    ${lastState.big_fan1_speed ?? "N/A"}`);
    console.log(`    Big Fan 2:    ${lastState.big_fan2_speed ?? "N/A"}`);
    if (lastState.spd_lvl !== undefined) {
        const speedNames = {
            1: "Silent",
            2: "Standard",
            3: "Sport",
            4: "Ludicrous"
        };
        console.log("------------------------------------------------------------------");
        console.log(`  Speed Level:    ${speedNames[lastState.spd_lvl] || lastState.spd_lvl} (${lastState.spd_mag ?? 100}%)`);
    }
    if (lastState.wifi_signal) {
        console.log("------------------------------------------------------------------");
        console.log(`  WiFi Signal:    ${lastState.wifi_signal}`);
    }
    if (lastState.print_error !== undefined && lastState.print_error !== 0) {
        console.log("------------------------------------------------------------------");
        console.log(`  ERROR CODE:     ${lastState.print_error}`);
    }
    if (lastState.lifecycle) {
        console.log(`  Lifecycle:      ${lastState.lifecycle}`);
    }
    console.log("==================================================================");
}
function printMenu() {
    console.log("\n------------------------------------------------------------------");
    console.log("  COMMANDS");
    console.log("------------------------------------------------------------------");
    console.log("  [r] Refresh (send pushall)    [s] Show state");
    console.log("  [d] Show diagnostics          [v] Toggle verbose mode");
    console.log("  [c] Clear screen              [j] Show raw JSON");
    console.log("  [p] Pause print               [u] Resume print");
    console.log("  [x] Stop print                [g] Send GCode");
    console.log("  [h] Home X (G28 X)            [t] Start print (file path)");
    console.log(`  [l] Toggle dump (${dumpEnabled ? "ON" : "OFF"})           [f] Show dump file path`);
    console.log("  [q] Quit");
    console.log("------------------------------------------------------------------");
    process.stdout.write("\n> ");
}
async function sendPushall() {
    if (!client?.connected) {
        log("Cannot send pushall: not connected", "ERROR");
        return;
    }
    const payload = {
        pushing: {
            sequence_id: sequenceIdCounter++,
            command: "pushall",
            version: 1,
            push_target: 1
        }
    };
    const topic = `device/${serial}/report`;
    const message = JSON.stringify(payload);
    log(`Sending pushall command (seq: ${payload.pushing.sequence_id})`, "DEBUG");
    writeToDump("OUT", topic, payload);
    client.publish(topic, message, {
        qos: 0
    }, (err)=>{
        if (err) {
            log(`Failed to send pushall: ${err.message}`, "ERROR");
        } else {
            log("Pushall command sent", "INFO");
        }
    });
}
async function sendPrintCommand(command, params) {
    if (!client?.connected) {
        log("Cannot send command: not connected", "ERROR");
        return;
    }
    const payload = {
        print: {
            command,
            sequence_id: sequenceIdCounter++,
            ...params
        }
    };
    const topic = `device/${serial}/report`;
    const message = JSON.stringify(payload);
    log(`Sending command: ${command} (seq: ${payload.print.sequence_id})`, "DEBUG");
    writeToDump("OUT", topic, payload);
    client.publish(topic, message, {
        qos: 0
    }, (err)=>{
        if (err) {
            log(`Failed to send command: ${err.message}`, "ERROR");
        } else {
            log(`Command '${command}' sent`, "INFO");
        }
    });
}
async function sendGcode(gcode) {
    await sendPrintCommand("gcode_line", {
        param: gcode
    });
}
function handleMessage(topic, message) {
    messageCount++;
    lastMessageTime = new Date();
    try {
        const payload = JSON.parse(message.toString());
        writeToDump("IN", topic, payload);
        if (payload.print?.command === "push_status") {
            lastState = payload.print;
            log(`State update received (gcode_state: ${lastState.gcode_state || "N/A"})`, "DEBUG");
        } else if (payload.print) {
            lastState = payload.print;
            log(`Print data received`, "DEBUG");
        } else if (payload.pushing) {
            log(`Pushing response received (seq: ${payload.pushing.sequence_id})`, "DEBUG");
        } else {
            log(`Unknown message type received`, "DEBUG");
        }
        if (isVerbose) {
            log(`Raw message: ${JSON.stringify(payload).substring(0, 200)}...`, "DEBUG");
        }
    } catch (error) {
        log(`Failed to parse message: ${error}`, "ERROR");
        writeToDump("IN", topic, {
            _raw: message.toString(),
            _error: String(error)
        });
    }
}
function connect() {
    const mqttUrl = `mqtts://${host}:${MQTT_PORT}`;
    const topic = `device/${serial}/report`;
    if (dumpEnabled) {
        initDumpFile();
    }
    log(`Connecting to ${mqttUrl}...`, "INFO");
    log(`Username: ${MQTT_USERNAME}`, "DEBUG");
    log(`Topic: ${topic}`, "DEBUG");
    client = _mqtt.default.connect(mqttUrl, {
        username: MQTT_USERNAME,
        password: accessCode,
        reconnectPeriod: RECONNECT_PERIOD,
        rejectUnauthorized: false,
        connectTimeout: 30000
    });
    client.on("connect", ()=>{
        connectionStartTime = new Date();
        log("MQTT connected successfully", "INFO");
        client.subscribe(topic, {
            qos: 0
        }, (err)=>{
            if (err) {
                log(`Failed to subscribe: ${err.message}`, "ERROR");
            } else {
                log(`Subscribed to ${topic}`, "INFO");
                setTimeout(()=>{
                    sendPushall();
                }, 500);
            }
        });
    });
    client.on("message", (topic, message)=>{
        handleMessage(topic, message);
    });
    client.on("error", (error)=>{
        log(`MQTT error: ${error.message}`, "ERROR");
    });
    client.on("disconnect", ()=>{
        log("MQTT disconnected", "WARN");
    });
    client.on("reconnect", ()=>{
        log("MQTT attempting to reconnect...", "INFO");
    });
    client.on("close", ()=>{
        log("MQTT connection closed", "WARN");
    });
    client.on("offline", ()=>{
        log("MQTT client offline", "WARN");
    });
}
const rl = _nodereadline.createInterface({
    input: process.stdin,
    output: process.stdout
});
async function handleCommand(input) {
    const cmd = input.trim().toLowerCase();
    switch(cmd){
        case "r":
            await sendPushall();
            break;
        case "s":
            clearScreen();
            printDiagnostics();
            printState();
            break;
        case "d":
            clearScreen();
            printDiagnostics();
            break;
        case "v":
            isVerbose = !isVerbose;
            log(`Verbose mode: ${isVerbose ? "ON" : "OFF"}`, "INFO");
            break;
        case "c":
            clearScreen();
            break;
        case "j":
            console.log("\n--- RAW STATE JSON ---");
            console.log(JSON.stringify(lastState, null, 2));
            console.log("--- END JSON ---");
            break;
        case "p":
            log("Sending pause command...", "INFO");
            await sendPrintCommand("pause");
            break;
        case "u":
            log("Sending resume command...", "INFO");
            await sendPrintCommand("resume");
            break;
        case "x":
            log("Sending stop command...", "INFO");
            await sendPrintCommand("stop");
            break;
        case "h":
            log("Sending G28 X (home X axis)...", "INFO");
            await sendGcode("G28 X");
            break;
        case "t":
            rl.question("Enter file path (e.g. cache/file.gcode): ", async (filePath)=>{
                if (filePath.trim()) {
                    log(`Starting print: ${filePath.trim()}`, "INFO");
                    await sendPrintCommand("project_file", {
                        param: `Metadata/plate_1.gcode`,
                        url: `file:///sdcard/${filePath.trim()}`,
                        subtask_name: _nodepath.basename(filePath.trim()),
                        bed_leveling: true,
                        flow_cali: true,
                        vibration_cali: true,
                        layer_inspect: false,
                        use_ams: true
                    });
                } else {
                    log("No file path entered", "WARN");
                }
                printMenu();
            });
            return;
        case "g":
            rl.question("Enter GCode: ", async (gcode)=>{
                if (gcode.trim()) {
                    await sendGcode(gcode.trim());
                }
                printMenu();
            });
            return;
        case "l":
            dumpEnabled = !dumpEnabled;
            if (dumpEnabled && !dumpStream) {
                initDumpFile();
            } else if (!dumpEnabled && dumpStream) {
                closeDumpFile();
            }
            log(`MQTT dump: ${dumpEnabled ? "ENABLED" : "DISABLED"}`, "INFO");
            break;
        case "f":
            if (dumpFilePath) {
                console.log(`\nDump file: ${dumpFilePath}`);
                console.log(`Messages dumped: ${dumpMessageCount}`);
            } else {
                console.log("\nNo dump file active.");
            }
            break;
        case "q":
            log("Disconnecting...", "INFO");
            closeDumpFile();
            if (client) {
                client.end(false, {}, ()=>{
                    log("Disconnected. Goodbye!", "INFO");
                    process.exit(0);
                });
            } else {
                process.exit(0);
            }
            return;
        default:
            if (cmd) {
                log(`Unknown command: ${cmd}`, "WARN");
            }
    }
    printMenu();
}
rl.on("line", (input)=>{
    handleCommand(input);
});
process.on("SIGINT", ()=>{
    log("\nReceived SIGINT. Shutting down...", "INFO");
    closeDumpFile();
    if (client) {
        client.end(false, {}, ()=>{
            process.exit(0);
        });
    } else {
        process.exit(0);
    }
});
process.on("SIGTERM", ()=>{
    log("\nReceived SIGTERM. Shutting down...", "INFO");
    closeDumpFile();
    if (client) {
        client.end(false, {}, ()=>{
            process.exit(0);
        });
    } else {
        process.exit(0);
    }
});
console.log("BAMBU MQTT DIAGNOSTIC CONSOLE");
console.log("=============================");
console.log("");
connect();
printMenu();

//# sourceMappingURL=bambu-mqtt-diagnostic.console.js.map