import ReceiptPrinterEncoder from '@point-of-sale/receipt-printer-encoder';
import { normalizeEncoderOptions } from '@/lib/thermal-printer/normalize-encoder-options';
import type { PaperSize } from '@/lib/thermal-printer/types';
import type { OrderListItem } from '@/types/order';

export type EncodeOrderReceiptOptions = {
    storeName: string;
    storeAddress: string;
    paperSize: PaperSize;
    language?: string | null;
    codepageMapping?: string | null;
};

export function getPaperColumns(paperSize: PaperSize): number {
    return paperSize === '58mm' ? 32 : 48;
}

function dashedLine(columns: number): string {
    return '-'.repeat(columns);
}

export function encodeOrderReceipt(
    order: OrderListItem,
    options: EncodeOrderReceiptOptions,
): Uint8Array {
    const columns = getPaperColumns(options.paperSize);
    const amountColumnWidth = 14;
    const labelColumnWidth = columns - amountColumnWidth;
    const encoderOptions = normalizeEncoderOptions({
        language: options.language,
        codepageMapping: options.codepageMapping,
    });

    const encoder = new ReceiptPrinterEncoder({
        language: encoderOptions.language,
        codepageMapping: encoderOptions.codepageMapping,
        columns,
    });

    const createdBy = order.created_by?.profile?.full_name
        ?? order.created_by?.username
        ?? '-';

    encoder.initialize()
        .align('center')
        .bold(true)
        .text('')
        .newline()
        .text(options.storeName)
        .newline()
        .bold(false)
        .newline();

    for (const addressLine of options.storeAddress.split('\n')) {
        const trimmed = addressLine.trim();

        if (trimmed) {
            encoder.align('center').text(trimmed).newline();
        }
    }

    encoder.align('center').line(dashedLine(columns));
    encoder.align('left');
    encoder.line(`No   : ${order.order_number}`);
    encoder.line(`Tgl  : ${order.created_at_formatted}`);

    if (order.customer) {
        encoder.line(`Cust : ${order.customer.name}`);
    }

    encoder
        .line(`Kasir: ${createdBy}`)
        .line(dashedLine(columns));

    for (const item of order.items) {
        const productName = item.product_variant?.product?.name ?? '-';
        const variantName = item.product_variant?.name ?? '-';

        encoder
            .line(productName)
            .line(`  ${variantName}`)
            .table(
                [
                    { width: labelColumnWidth, align: 'left' },
                    { width: amountColumnWidth, align: 'right' },
                ],
                [[
                    `${item.quantity_formatted} x ${item.unit_price_formatted}`,
                    (rowEncoder) => rowEncoder.bold().text(item.subtotal_formatted).bold(false),
                ]],
            )
            .newline();
    }

    encoder.line(dashedLine(columns));

    const summaryRows: string[][] = [
        ['Subtotal', order.subtotal_formatted],
        ['Diskon', order.discount_formatted],
    ];

    if (order.nego_price_formatted) {
        summaryRows.push(['Harga Nego', order.nego_price_formatted]);
    }

    summaryRows.push(['Total', order.total_amount_formatted]);

    encoder.table(
        [
            { width: labelColumnWidth, align: 'left' },
            { width: amountColumnWidth, align: 'right' },
        ],
        summaryRows,
    );

    if (order.notes) {
        encoder
            .newline()
            .line('Catatan:')
            .line(order.notes);
    }

    encoder
        .newline()
        .line(dashedLine(columns))
        .align('center')
        .line('Terima kasih atas kunjungannya')
        .line('Silakan berbelanja kembali')
        .newline(3)
        .cut();

    return encoder.encode();
}
