import { computed, ref } from 'vue';
import { encodeOrderReceipt } from '@/lib/thermal-printer/encode-order-receipt';
import { normalizeEncoderOptions } from '@/lib/thermal-printer/normalize-encoder-options';
import {
    connectBluetooth,
    connectionState,
    connectUsb,
    disconnect as disconnectTransport,
    getBluetoothEncoderSettings,
    isWebBluetoothSupported,
    isWebSerialSupported,
    restoreConnection,
    sendPrintData,
    tryReconnect as tryReconnectTransport,
} from '@/lib/thermal-printer/stable-transport';
import type { PaperSize } from '@/lib/thermal-printer/types';
import type { OrderListItem } from '@/types/order';

const connecting = ref(false);

async function withConnecting<T>(callback: () => Promise<T>): Promise<T> {
    connecting.value = true;

    try {
        return await callback();
    } finally {
        connecting.value = false;
    }
}

export type PrintOrderReceiptOptions = {
    order: OrderListItem;
    paperSize: PaperSize;
    storeName: string;
    storeAddress: string;
};

async function printOrderReceipt(options: PrintOrderReceiptOptions): Promise<void> {
    const { order, paperSize, storeName, storeAddress } = options;
    let connection = connectionState.value;

    if (!connection) {
        const restored = await restoreConnection();
        connection = connectionState.value;

        if (!restored || !connection) {
            throw new Error('Printer belum terhubung. Hubungkan printer terlebih dahulu.');
        }
    }

    const bluetoothSettings = connection === 'bluetooth'
        ? getBluetoothEncoderSettings()
        : null;
    const encoderOptions = normalizeEncoderOptions({
        language: bluetoothSettings?.language,
        codepageMapping: bluetoothSettings?.codepageMapping,
    });

    const encoded = encodeOrderReceipt(order, {
        storeName,
        storeAddress,
        paperSize,
        language: connection === 'bluetooth' ? encoderOptions.language : undefined,
        codepageMapping: connection === 'bluetooth' ? encoderOptions.codepageMapping : undefined,
    });

    await sendPrintData(encoded);
}

export function useThermalPrinter() {
    const isConnected = computed(() => connectionState.value !== null);

    const connectionLabel = computed(() => {
        const connection = connectionState.value;

        if (connection === 'usb') {
            return 'USB';
        }

        if (connection === 'bluetooth') {
            return 'Bluetooth';
        }

        return null;
    });

    return {
        activeConnection: connectionState,
        isConnected,
        connectionLabel,
        connecting,
        connectUsb: () => withConnecting(connectUsb),
        connectBluetooth: () => withConnecting(connectBluetooth),
        tryReconnect: () => withConnecting(tryReconnectTransport),
        disconnect: disconnectTransport,
        printOrderReceipt,
        supportsUsb: isWebSerialSupported(),
        supportsBluetooth: isWebBluetoothSupported(),
    };
}

export function getPaperSizeLabel(paperSize: PaperSize): string {
    return paperSize;
}
