import qz from 'qz-tray';
import { usePage } from '@inertiajs/vue3';
import { ref } from 'vue';

declare const route: any;

export const isPrinting = ref(false);
export const printStatus = ref('');

export interface PrintSettings {
    method: 'browser' | 'qz';
    posPrinter: string;
    kitchenPrinter: string;
    autoPrintPos: boolean;
    autoPrintKitchen: boolean;
    zoomScale: number;
}

const STORAGE_KEY = 'cafepos_print_settings';

const DEFAULT_SETTINGS: PrintSettings = {
    method: 'browser',
    posPrinter: '',
    kitchenPrinter: '',
    autoPrintPos: false,
    autoPrintKitchen: false,
    zoomScale: 100
};

// Get current settings from localStorage
export function getPrintSettings(): PrintSettings {
    try {
        const stored = localStorage.getItem(STORAGE_KEY);
        if (stored) {
            return { ...DEFAULT_SETTINGS, ...JSON.parse(stored) };
        }
    } catch (e) {
        console.error('Failed to read print settings from localStorage:', e);
    }
    return DEFAULT_SETTINGS;
}

// Save settings to localStorage
export function savePrintSettings(settings: PrintSettings): void {
    try {
        localStorage.setItem(STORAGE_KEY, JSON.stringify(settings));
    } catch (e) {
        console.error('Failed to save print settings to localStorage:', e);
    }
}

// Connect to QZ Tray websocket server
export async function connectQZ(): Promise<boolean> {
    // Configure QZ security promises if certificate is shared in Inertia props
    const page = usePage();
    const qzCert = (page.props as any).qz_cert;
    const qzAlgo = (page.props as any).qz_algo || 'sha256';

    if (qzCert) {
        // Set signature algorithm
        qz.security.setSignatureAlgorithm(qzAlgo.toUpperCase());

        // Set certificate promise
        qz.security.setCertificatePromise((resolve: any) => {
            resolve(qzCert);
        });

        // Set signature promise
        const csrfToken = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content') || '';
        qz.security.setSignaturePromise((toSign: string) => {
            return (resolve: any, reject: any) => {
                fetch(route('qz-tray.sign'), {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                        'X-CSRF-TOKEN': csrfToken,
                        'Accept': 'application/json',
                    },
                    body: JSON.stringify({ payload: toSign })
                })
                .then(async (res) => {
                    if (!res.ok) {
                        const errData = await res.json();
                        throw new Error(errData.message || 'Signature endpoint failed.');
                    }
                    return res.json();
                })
                .then((data) => {
                    if (data.success) {
                        resolve(data.signature);
                    } else {
                        reject(data.message || 'Signing failed');
                    }
                })
                .catch((err) => {
                    reject(err.message || err);
                });
            };
        });
    }

    if (qz.websocket.isActive()) {
        return true;
    }
    try {
        await qz.websocket.connect();
        return true;
    } catch (err) {
        console.warn('QZ Tray is not running or connection failed:', err);
        return false;
    }
}

// Disconnect from QZ Tray
export async function disconnectQZ(): Promise<void> {
    if (qz.websocket.isActive()) {
        await qz.websocket.disconnect();
    }
}

// Fetch list of installed printer names on the OS
export async function getAvailablePrinters(): Promise<string[]> {
    const isConnected = await connectQZ();
    if (!isConnected) {
        throw new Error('QZ Tray is not connected');
    }
    return await qz.printers.find();
}

// Print raw HTML string via QZ Tray
export async function printHtmlViaQz(printerName: string, htmlContent: string, zoomScale: number = 100): Promise<void> {
    const isConnected = await connectQZ();
    if (!isConnected) {
        throw new Error('QZ Tray is not connected');
    }

    const zoomRatio = (zoomScale && zoomScale > 0 ? zoomScale : 100) / 100;
    const widthPercent = (100 / zoomRatio).toFixed(2);

    const scaledHtml = `
        <div style="zoom: ${zoomRatio}; -webkit-transform: scale(${zoomRatio}); transform: scale(${zoomRatio}); transform-origin: top left; width: ${widthPercent}%; font-family: 'Courier New', Courier, monospace;">
            ${htmlContent}
        </div>
    `;

    const config = qz.configs.create(printerName, {
        margins: 0,
        orientation: 'portrait',
        size: { width: 58, height: 297 },
        units: 'mm',
        scaleContent: true
    });

    const printData = [{
        type: 'html',
        format: 'plain',
        data: scaledHtml,
        options: {
            pageWidth: 58,
            margins: 0,
        }
    }];

    await qz.print(config, printData);
}

// Loads a print URL inside a hidden iframe, extracts its content, and prints it via QZ Tray
export function printUrlViaQz(printerName: string, url: string, zoomScale: number = 100): Promise<void> {
    return new Promise((resolve, reject) => {
        // Create hidden iframe
        const iframe = document.createElement('iframe');
        iframe.style.position = 'absolute';
        iframe.style.width = '0px';
        iframe.style.height = '0px';
        iframe.style.border = 'none';
        iframe.style.visibility = 'hidden';
        iframe.src = url;
        document.body.appendChild(iframe);

        iframe.onload = async () => {
            try {
                printStatus.value = 'Mengunduh format struk...';
                const doc = iframe.contentDocument || iframe.contentWindow?.document;
                if (!doc) {
                    throw new Error('Could not access iframe document');
                }

                // Extract and map all stylesheets to absolute URLs so QZ Tray can load styling correctly
                const headElements = doc.head.querySelectorAll('link[rel="stylesheet"], style');
                let stylesHtml = '';
                headElements.forEach(el => {
                    if (el.tagName.toLowerCase() === 'link') {
                        const href = el.getAttribute('href');
                        if (href && href.startsWith('/')) {
                            const absoluteHref = window.location.origin + href;
                            stylesHtml += `<link rel="stylesheet" href="${absoluteHref}">`;
                        } else {
                            stylesHtml += el.outerHTML;
                        }
                    } else {
                        stylesHtml += el.outerHTML;
                    }
                });

                // Clone the body and resolve any relative image sources to absolute URLs (e.g. logos)
                const bodyClone = doc.body.cloneNode(true) as HTMLElement;
                const images = bodyClone.querySelectorAll('img');
                images.forEach(img => {
                    const src = img.getAttribute('src');
                    if (src && src.startsWith('/')) {
                        img.setAttribute('src', window.location.origin + src);
                    }
                });

                // Combine CSS styles and the receipt markup
                const htmlContent = stylesHtml + bodyClone.innerHTML;
                if (!bodyClone.innerHTML || bodyClone.innerHTML.trim() === '') {
                    throw new Error('Iframe loaded but content is empty');
                }

                // Send to QZ Tray
                printStatus.value = 'Mengirim data ke printer...';
                await printHtmlViaQz(printerName, htmlContent, zoomScale);

                // Clean up
                document.body.removeChild(iframe);
                resolve();
            } catch (err) {
                if (iframe.parentNode) {
                    document.body.removeChild(iframe);
                }
                reject(err);
            }
        };

        iframe.onerror = (err) => {
            if (iframe.parentNode) {
                document.body.removeChild(iframe);
            }
            reject(new Error('Failed to load print preview iframe'));
        };
    });
}

// High-level print command with fallback
export async function printReceipt(
    transactionId: number,
    type: 'pos' | 'kitchen',
    cashReceived?: number,
    change?: number
): Promise<{ success: boolean; method: 'qz' | 'browser'; error?: string }> {
    const settings = getPrintSettings();
    
    // Resolve route URL
    let url = '';
    if (type === 'pos') {
        const params: Record<string, any> = { transaction: transactionId };
        if (cashReceived !== undefined && cashReceived !== null) params.cash_received = cashReceived;
        if (change !== undefined && change !== null) params.change = change;
        url = route('transactions.print', params);
    } else {
        url = route('transactions.kitchen-print', transactionId);
    }

    try {
        isPrinting.value = true;

        // Try QZ Tray if configured
        if (settings.method === 'qz') {
            printStatus.value = 'Menghubungkan ke QZ Tray...';
            const printerName = type === 'pos' ? settings.posPrinter : settings.kitchenPrinter;
            if (!printerName) {
                return {
                    success: false,
                    method: 'qz',
                    error: `Printer name for ${type === 'pos' ? 'POS' : 'Kitchen'} is not configured in settings.`
                };
            }

            // Append raw=true parameter to force raw rendering in the iframe
            const rawUrl = url.includes('?') ? `${url}&raw=true` : `${url}?raw=true`;
            await printUrlViaQz(printerName, rawUrl, settings.zoomScale ?? 100);
            return { success: true, method: 'qz' };
        }

        // Default to browser print
        printStatus.value = 'Membuka dialog cetak browser...';
        window.open(url, '_blank');
        // Add a brief delay so the user sees the "Membuka dialog..." message
        await new Promise(resolve => setTimeout(resolve, 800));
        return { success: true, method: 'browser' };
    } catch (err: any) {
        console.error('QZ Tray print failed, falling back to browser print:', err);
        // Fallback to browser print on failure
        printStatus.value = 'Dialihkan ke dialog cetak browser...';
        window.open(url, '_blank');
        await new Promise(resolve => setTimeout(resolve, 800));
        return {
            success: true,
            method: 'browser',
            error: `QZ Tray print failed: ${err.message || err}. Opened print dialog instead.`
        };
    } finally {
        isPrinting.value = false;
        printStatus.value = '';
    }
}
