// cetak.js - v4.2 Andal (Otomatis Hapus Antrian Saat Gagal)

global.TextDecoder = require('text-encoding').TextDecoder;
global.TextEncoder = require('text-encoding').TextEncoder;
const { WebSocketServer } = require('ws');
const fs = require('fs');
const path = require('path');
const { exec } = require('child_process');

const VERIFICATION_DELAY = 2000; // Jeda verifikasi 2 detik (dalam milidetik)

const wss = new WebSocketServer({ port: 8080 });

wss.on('connection', ws => {
  console.log('Client terhubung');
  ws.on('message', message => processRequest(ws, message));
});

function processRequest(ws, message) {
    try {
      const data = JSON.parse(message.toString());
      const actionType = data.action || '';
      
      const port = data.port;
      const printerName = data.nama_printer;

      if (!port || !printerName) {
        return ws.send(JSON.stringify({ type: 'error', message: `Request tidak lengkap. 'port' dan 'nama_printer' wajib diisi.` }));
      }

      if (actionType.startsWith('cetak')) {
        handlePrint(ws, port, printerName, data);
      } else if (actionType === 'cek_spooler') {
        checkSpooler(ws, printerName);
      } else if (actionType === 'hapus_antrian') {
        clearQueue(ws, printerName);
      }
    } catch (e) {
      ws.send(JSON.stringify({ type: 'error', message: `Request tidak valid: ${e.message}` }));
    }
}

/**
 * PERUBAHAN UTAMA DI FUNGSI INI
 * Menangani proses cetak. Jika gagal, otomatis akan membersihkan antrian printer yang bermasalah.
 */
function handlePrint(ws, port, printerName, data) {
    const tempFile = path.join(process.env.TEMP || '/tmp', `print_${Date.now()}.dat`);

    try {
        fs.writeFileSync(tempFile, Buffer.from(data.printData+'0A0A0A0A0A0A' + '1D5630', 'hex'));
    } catch (writeError) {
        return ws.send(JSON.stringify({ type: 'error', message: 'Gagal membuat file sementara.' }));
    }

    const printCommand = `type "${tempFile}" > ${port}`;
    
    exec(printCommand, (error) => {
        fs.unlinkSync(tempFile); // Selalu hapus file sementara
        
        // JIKA TERJADI ERROR SAAT MENCETAK
        if (error) {
            // 1. Buat pesan error yang spesifik dan informatif.
            const errorMessage = `Gagal mencetak. Printer '${printerName}' (${port}) kemungkinan offline atau tidak tersambung.`;
            console.error(errorMessage, `Detail: ${error.message}`);

            // 2. Langsung jalankan perintah untuk membersihkan antrian printer yang bermasalah.
            const clearQueueCommand = `powershell -command "Get-PrintJob -PrinterName '${printerName}' | Remove-PrintJob -Confirm:$false"`;
            exec(clearQueueCommand, (clearError) => {
                if (clearError) {
                    console.error(`Gagal saat mencoba membersihkan antrian untuk ${printerName}:`, clearError.message);
                } else {
                    console.log(`Antrian untuk printer '${printerName}' berhasil dibersihkan setelah kegagalan cetak.`);
                }
                // 3. Kirim pesan error UTAMA kembali ke klien, terlepas dari apakah pembersihan antrian berhasil atau tidak.
                return ws.send(JSON.stringify({ type: 'error', message: errorMessage }));
            });
            return; // Hentikan eksekusi lebih lanjut di blok ini.
        }

        // JIKA PROSES CETAK AWAL BERHASIL, LANJUTKAN VERIFIKASI
        ws.send(JSON.stringify({ type: 'info', message: `✅ Terkirim ke ${port}. Memverifikasi status di '${printerName}'...` }));
        setTimeout(() => verifyPrintStatus(ws, printerName), VERIFICATION_DELAY);
    });
}

function verifyPrintStatus(ws, printerName) {
    const verifyCommand = `powershell -command "Get-PrintJob -PrinterName '${printerName}' | Select-Object ID, DocumentName, JobStatus | ConvertTo-Json"`;
    exec(verifyCommand, (psError, psStdout) => {
        if (psError) return ws.send(JSON.stringify({ type: 'error', message: `Gagal memeriksa status printer: ${psError.message}` }));
        
        // Jika tidak ada output, berarti antrian kosong dan cetak berhasil.
        if (!psStdout.trim()) {
            return ws.send(JSON.stringify({ type: 'success', message: `✅ Cetak berhasil di '${printerName}'!` }));
        }

        // Jika ada output, kemungkinan ada pekerjaan yang tertahan.
        try {
            const jobs = JSON.parse(psStdout);
            if ((Array.isArray(jobs) ? jobs.length > 0 : jobs)) {
                // Buat pesan error spesifik jika verifikasi menemukan pekerjaan tertahan
                const errorMessage = `Gagal mencetak. Printer '${printerName}' mengalami error atau pekerjaan tertahan.`;
                ws.send(JSON.stringify({ type: 'error', message: errorMessage, data: jobs }));

                // Otomatis bersihkan antrian jika verifikasi gagal
                clearQueue(ws, printerName, true); // `true` menandakan pembersihan otomatis
                return;
            }
            return ws.send(JSON.stringify({ type: 'success', message: `✅ Cetak berhasil di '${printerName}'!` }));
        } catch (e) {
            return ws.send(JSON.stringify({ type: 'error', message: `Status printer tidak diketahui.` }));
        }
    });
}

function checkSpooler(ws, printerName) {
    const checkCommand = `powershell -command "Get-PrintJob -PrinterName '${printerName}' | Select-Object ID, DocumentName, JobStatus | ConvertTo-Json"`;
    ws.send(JSON.stringify({ type: 'info', message: `Mengecek antrian di ${printerName}...` }));
    exec(checkCommand, (psError, psStdout) => {
        if (psError) return ws.send(JSON.stringify({ type: 'error', message: `Gagal memeriksa status: ${psError.message}` }));
        if (!psStdout.trim()) return ws.send(JSON.stringify({ type: 'success', message: `✅ Antrian di ${printerName} bersih.` }));
        try {
            return ws.send(JSON.stringify({ type: 'info', message: `⚠️ Antrian di ${printerName} berisi pekerjaan:`, data: JSON.parse(psStdout) }));
        } catch (e) {
            return ws.send(JSON.stringify({ type: 'error', message: `Gagal memproses status antrian.` }));
        }
    });
}

function clearQueue(ws, printerName, isAutomatic = false) {
    const clearQueueCommand = `powershell -command "Get-PrintJob -PrinterName '${printerName}' | Remove-PrintJob -Confirm:$false"`;
    
    // Jika tidak otomatis, kirim pesan "sedang membersihkan"
    if (!isAutomatic) {
        ws.send(JSON.stringify({ type: 'info', message: `Membersihkan antrian di ${printerName}...` }));
    }

    exec(clearQueueCommand, (error) => {
        if (error) {
            console.error(`Gagal membersihkan antrian untuk ${printerName}:`, error.message);
            if (!isAutomatic) {
                ws.send(JSON.stringify({ type: 'error', message: `Gagal membersihkan antrian: ${error.message}` }));
            }
            return;
        }
        console.log(`Antrian untuk ${printerName} berhasil dibersihkan.`);
        if (!isAutomatic) {
            ws.send(JSON.stringify({ type: 'success', message: `✅ Antrian di ${printerName} berhasil dibersihkan!` }));
        }
    });
}

console.log('Server print (v4.2 - Andal) berjalan di port 8080');