import { defineStore } from "pinia"
import {
    Utils,
    RequestCommandId,
    ResponseCommandId,
    NiimbotBluetoothClient,
    NiimbotSerialClient
} from "@mmote/niimbluelib"
import { useToast } from "#imports"

export const useLabelPrinterStore = defineStore("labelPrinter", {
    state: () => ({
        client: null as NiimbotBluetoothClient | NiimbotSerialClient | null,
        connected: false,
        connectLoading: false,
        transportLastUsed: "",
        printProgress: 0,
        info: {} as any
    }),

    actions: {

        /** Logging Helper */
        logger(...args: any[]) {
            console.debug("[Printer]", ...args)
        },

        /** --- Client erzeugen --- */
        newClient(transport: "ble" | "serial" = "serial") {
            const toast = useToast()

            // alten Client trennen
            if (this.client) {
                try { this.client.disconnect() } catch {}
            }

            // neuen Client erzeugen
            this.client =
                transport === "ble"
                    ? new NiimbotBluetoothClient()
                    : new NiimbotSerialClient()

            /** Events registrieren */

            this.client.on("printerinfofetched", (e) => {
                console.log("printerInfoFetched")
                console.log(e.info)
                this.info = e.info
            })

            this.client.on("connect", () => {
                this.connected = true
                toast.add({ title: "Drucker verbunden" })
                this.logger("connected")
            })

            this.client.on("disconnect", () => {
                this.connected = false
                toast.add({ title: "Drucker getrennt" })
                this.logger("disconnected")
            })

            this.client.on("printprogress", (e) => {
                if (e.pagePrintProgress) this.printProgress = e.pagePrintProgress
                this.logger(
                    `Page ${e.page}/${e.pagesTotal}, Page print ${e.pagePrintProgress}%, Page feed ${e.pageFeedProgress}%`
                )
            })

            return this.client
        },

        /** --- Verbinden --- */
        async connect(transport: "ble" | "serial" = "serial") {
            const toast = useToast()

            this.connectLoading = true

            this.newClient(transport)

            try {
                await this.client!.connect()
                this.transportLastUsed = transport
                this.connectLoading = false
            } catch (err) {
                console.error("[Printer] Connect failed:", err)
                toast.add({ title: "Verbindung fehlgeschlagen", color: "red" })
                this.connectLoading = false
            }
        },

        /** --- Trennen --- */
        async disconnect({ forget = false } = {}) {
            const toast = useToast()
            this.logger("Disconnect requested…")

            if (!this.client) return

            try {
                // Timer stoppen
                try {
                    if (this.client.heartbeatTimer) {
                        clearInterval(this.client.heartbeatTimer)
                        this.client.heartbeatTimer = null
                    }
                    if (this.client.abstraction?.statusPollTimer) {
                        clearInterval(this.client.abstraction.statusPollTimer)
                        this.client.abstraction.statusPollTimer = null
                    }
                } catch {}

                await this.client.disconnect?.()

                // Serial-Port schließen
                const port = (this.client as any).port
                if (port) {
                    try {
                        if (port.readable) port.readable.cancel?.()
                        if (port.writable) await port.writable.abort?.()
                        await port.close?.()

                        if (forget && navigator.serial?.forgetPort) {
                            await navigator.serial.forgetPort(port)
                        }
                    } catch (err) {
                        this.logger("Error closing port:", err)
                    }
                }

                // BLE GATT
                if (
                    this.client instanceof NiimbotBluetoothClient &&
                    this.client.device?.gatt?.connected
                ) {
                    try {
                        this.client.device.gatt.disconnect()
                    } catch {}
                }

                this.connected = false
                this.client = null
                toast.add({ title: "Drucker getrennt" })
            } catch (err) {
                console.error("[Printer] Disconnect error", err)
                toast.add({ title: "Fehler beim Trennen", color: "red" })
            }
        },

        /** Hilfsfunktion: EncodedImage reparieren */
        reviveEncodedImage(encoded: any) {
            if (!encoded?.rowsData) return encoded
            for (const row of encoded.rowsData) {
                if (row.rowData && !(row.rowData instanceof Uint8Array)) {
                    row.rowData = new Uint8Array(Object.values(row.rowData))
                }
            }
            return encoded
        },

        /** --- Drucken --- */
        async print(encoded: any, options?: { density?: number; pages?: number }) {
            const toast = useToast()

            if (!this.client) throw new Error("Kein Drucker verbunden")

            const fixed = this.reviveEncodedImage(encoded)
            const taskName = this.client.getPrintTaskType() ?? "B1"

            const task = this.client.abstraction.newPrintTask(taskName, {
                totalPages: options?.pages ?? 1,
                statusPollIntervalMs: 100,
                statusTimeoutMs: 8000,
                density: options?.density ?? 5
            })

            try {
                this.printProgress = 0
                await task.printInit()
                await task.printPage(fixed, options?.pages ?? 1)
                await task.waitForFinished()
                toast.add({ title: "Druck abgeschlossen" })
            } catch (e) {
                console.error("[Printer] print error", e)
                toast.add({ title: "Druckfehler", color: "red" })
            } finally {
                await task.printEnd()
            }
        }
    }
})
