/**
 * report.js
 * Skrip ini berisi logika untuk menghasilkan laporan penjualan.
 * Dibuat berdasarkan logika yang ada di file HTML.
 * Ketergantungan:
 * - File ini membutuhkan fungsi `ambil_select(table, query)` yang diasumsikan
 * tersedia secara global (misalnya dari `crud.js`) untuk mengambil data dari database.
 * Cara Penggunaan:
 * Panggil fungsi `generateReport(options)` dengan objek opsi yang sesuai.
 */

// Variabel global untuk brand dan cabang, diambil dari localStorage
// let xbrand = '001', xcab = '002'; // Nilai default jika localStorage tidak tersedia
// try {
//     const xposData = localStorage.getItem('xpos');
//     if (xposData) {
//         const xpos = JSON.parse(xposData);
//         xbrand = xpos.brand || '001';
//         xcab = xpos.cab || '002';
//     }
// } catch (error) {
//     console.error("Gagal mengakses localStorage di report.js:", error);
// }

// =============================================
// FUNGSI-FUNGSI UTILITAS PENDUKUNG
// =============================================

/**
 * Menambahkan padding di sebelah kanan string.
 * @param {string|number} str Teks input.
 * @param {number} len Panjang total yang diinginkan.
 * @param {string} [char=' '] Karakter untuk padding.
 * @returns {string} String yang sudah diformat.
 */
const padRight = (str, len, char = ' ') => String(str).padEnd(len, char);

/**
 * Menambahkan padding di sebelah kiri string.
 * @param {string|number} str Teks input.
 * @param {number} len Panjang total yang diinginkan.
 * @param {string} [char=' '] Karakter untuk padding.
 * @returns {string} String yang sudah diformat.
 */
const padLeft = (str, len, char = ' ') => String(str).padStart(len, char);

/**
 * Memformat angka ke format mata uang Indonesia (IDR).
 * @param {number} num Angka yang akan diformat.
 * @returns {string} Angka dalam format string.
 */
const formatNumber = (num) => new Intl.NumberFormat('id-ID').format(Math.round(num));

/**
 * Membuat garis pemisah.
 * @param {string} [char='-'] Karakter untuk garis.
 * @returns {string} String berisi garis pemisah.
 */
const line = (char = '-') => char.repeat(42) + '\n';


// =============================================
// FUNGSI UTAMA PEMBUATAN LAPORAN
// =============================================

/**
 * Menghasilkan teks laporan penjualan berdasarkan opsi yang diberikan.
 * @param {object} options Opsi untuk filter laporan.
 * @param {boolean} options.isClosingMode Apakah ini mode closing kasir.
 * @param {string} [options.registerNomor] Nomor register jika filter per register.
 * @param {string} [options.startDate] Tanggal mulai (YYYY-MM-DD).
 * @param {string} [options.endDate] Tanggal akhir (YYYY-MM-DD).
 * @param {string} [options.kasir] Nama kasir ('All' atau nama spesifik).
 * @param {string} [options.tanggal] Tanggal closing (untuk mode closing).
 * @param {string} [options.namaKasir] Nama kasir (untuk mode closing).
 * @param {number} [options.saldoAwal] Saldo awal (untuk mode closing).
 * @param {number} [options.saldoAkhir] Saldo akhir (untuk mode closing).
 * @returns {Promise<string>} Teks laporan yang sudah diformat.
 */
async function generateReport(options) {
    // Membangun klausa WHERE untuk query SQL
    let whereClause = `brand='${xbrand}' AND cab='${xcab}' AND batal=0`;
    if (options.registerNomor) {
        whereClause += ` AND register='${options.registerNomor}'`;
    } else {
        whereClause += ` AND tanggal BETWEEN '${options.startDate}' AND '${options.endDate}'`;
        if (options.kasir && options.kasir !== 'All' && options.kasir !== 'Semua Kasir') {
            // Logika filter kasir bisa ditambahkan di sini jika diperlukan
            // whereClause += ` AND user='${options.kasir}'`; // Contoh jika 'kasir' adalah kode user
        }
    }

    const jualQuery = `SELECT * FROM jual WHERE ${whereClause}`;
    
    // Mengambil data secara paralel
    const tipeTransaksiPromise = ambil_select('tipe_transaksi', 'SELECT kode, nama FROM tipe_transaksi');
    const jualPromise = ambil_select('jual', jualQuery);
    
    // Menunggu kedua promise selesai
    const [jualResult, tipeTransaksiResult] = await Promise.all([
        Promise.resolve(jualPromise), 
        Promise.resolve(tipeTransaksiPromise)
    ]);

    const jualData = JSON.parse(jualResult);
    const tipeTransaksiMap = JSON.parse(tipeTransaksiResult).reduce((map, item) => ({...map, [item.kode]: item.nama }), {});

    if (!jualData || jualData.length === 0) {
        return 'Tidak ada data penjualan yang cocok dengan filter yang dipilih.';
    }

    // Mengambil semua item pesanan (pesani) berdasarkan nomor faktur
    const allNomor = jualData.map(j => `'${j.nomor}'`).join(',');
    const pesaniResult = await Promise.resolve(ambil_select('pesani', `SELECT * FROM pesani WHERE nomor IN (${allNomor})`));
    const pesaniData = JSON.parse(pesaniResult);

    // Inisialisasi variabel untuk kalkulasi
    let totalRevenue = 0, totalService = 0, totalTax = 0, totalDiscFaktur = 0, totalDiscItem = 0;
    const totalTransactions = jualData.length;
    const paymentSummary = {}, salesByCategory = {}, discSummary = {}, salesByTipe = {};

    // Proses data penjualan (header)
    jualData.forEach(jual => {
        const amount = parseFloat(jual.jumlah) || 0;
        totalRevenue += amount;
        totalService += parseFloat(jual.tserv) || 0;
        totalTax += parseFloat(jual.ttax) || 0;
        totalDiscFaktur += parseFloat(jual.diskrupiah) || 0;

        let paymentType = 'CASH';
        if (jual.meja && ['GOJEK', 'GRAB', 'SHOPEEFOOD'].includes(jual.meja.toUpperCase())) {
            paymentType = jual.meja.toUpperCase();
        } else {
            const paymentRecord = pesaniData.find(p => p.nomor === jual.nomor && !p.kode);
            if (paymentRecord) paymentType = paymentRecord.name.toUpperCase();
        }
        if (!paymentSummary[paymentType]) paymentSummary[paymentType] = { count: 0, total: 0 };
        paymentSummary[paymentType].count++;
        paymentSummary[paymentType].total += amount;

        const tipeNama = tipeTransaksiMap[jual.tipe] || `TIPE LAIN (${jual.tipe})`;
        if (!salesByTipe[tipeNama]) salesByTipe[tipeNama] = { count: 0, total: 0 };
        salesByTipe[tipeNama].count++;
        salesByTipe[tipeNama].total += amount;
    });

    // Proses data item pesanan (detail)
    pesaniData.forEach(item => {
        if (item.kode) { // Hanya proses item barang, bukan pembayaran
            const disc = parseFloat(item.disc) || 0;
            totalDiscItem += disc;
            if (disc > 0) {
                const discName = `(I) ${item.dname || item.name}`;
                if (!discSummary[discName]) discSummary[discName] = { count: 0, total: 0 };
                discSummary[discName].count += parseInt(item.quantity);
                discSummary[discName].total += disc;
            }
            const categoryName = item.group_name || 'UNCATEGORIZED';
            if (!salesByCategory[categoryName]) salesByCategory[categoryName] = { count: 0, total: 0 };
            salesByCategory[categoryName].count += parseInt(item.quantity);
            salesByCategory[categoryName].total += parseFloat(item.jumlah);
        }
    });

    const netSales = totalRevenue - totalService - totalTax;
    const totalSalesGross = netSales + totalDiscItem + totalDiscFaktur;

    // Membangun teks laporan
    let reportText = '';
    reportText += `${'Nama Resto'.padStart(26)}\n${'Alamat Resto'.padStart(27)}\n\n`;

    if (options.isClosingMode) {
        reportText += 'LAPORAN CLOSING KASIR\n';
        reportText += `${padRight('Tanggal', 12)}: ${options.tanggal}\n`;
        reportText += `${padRight('Kasir', 12)}: ${options.namaKasir}\n`;
        reportText += `${padRight('NO REGISTER', 12)}: ${options.registerNomor}\n\n`;
    } else {
        reportText += `Tanggal : ${options.startDate} s/d ${options.endDate}\n`;
        reportText += `Kasir   : ${options.kasir || 'All'}\n\n`;
    }

    reportText += `${padRight('TOTAL SALES', 15)}: ${padLeft(totalTransactions, 3)} ${padLeft(formatNumber(totalSalesGross), 18)}\n`;
    reportText += `${padRight('DISC ITEM', 15)}: ${padLeft(formatNumber(totalDiscItem), 24)}\n`;
    reportText += `${padRight('DISC FAKTUR', 15)}: ${padLeft(formatNumber(totalDiscFaktur), 24)}\n`;
    reportText += padLeft(line('-'), 42);
    reportText += `${padRight('NET SALES', 15)}: ${padLeft(formatNumber(netSales), 24)}\n`;
    reportText += `${padRight('SERVICE', 15)}: ${padLeft(formatNumber(totalService), 24)}\n`;
    reportText += `${padRight('PAJAK REST', 15)}: ${padLeft(formatNumber(totalTax), 24)}\n`;
    reportText += padLeft(line('-'), 42);
    reportText += `${padRight('TOTAL REVENUE', 15)}: ${padLeft(formatNumber(totalRevenue), 24)}\n\n`;

    reportText += 'RINCIAN PEMBAYARAN\n';
    Object.keys(paymentSummary).sort().forEach(type => {
        const p = paymentSummary[type];
        reportText += `${padRight(type, 20)} ${padLeft(p.count, 3)} ${padLeft(formatNumber(p.total), 16)}\n`;
    });
    reportText += padLeft(line('='), 42);
    reportText += `${padRight('TOTAL PAYMENT', 20)} ${padLeft(formatNumber(totalRevenue), 20)}\n\n`;

    if (options.isClosingMode) {
        const saldoAwal = parseFloat(options.saldoAwal) || 0;
        const saldoAkhir = parseFloat(options.saldoAkhir) || 0;
        const jumlah = saldoAwal + totalRevenue;
        const selisih = saldoAkhir - jumlah;
        reportText += `${padRight('SALDO AWAL', 15)} ${padLeft(formatNumber(saldoAwal), 26)}\n`;
        reportText += `${padRight('JUMLAH', 15)} ${padLeft(formatNumber(jumlah), 26)}\n`;
        reportText += `${padRight('SALDO AKHIR', 15)} ${padLeft(formatNumber(saldoAkhir), 26)}\n`;
        reportText += `${padRight('SELISIH', 15)} ${padLeft(formatNumber(selisih), 26)}\n\n`;
    }
    
    // Detail Laporan Tambahan
    if (Object.keys(salesByTipe).length > 0) {
        reportText += 'Sales By Tipe Transaksi\n' + line('-');
        let totalTipeCount = 0, totalTipeAmount = 0;
        Object.keys(salesByTipe).sort().forEach(name => {
            const tipe = salesByTipe[name];
            totalTipeCount += tipe.count; totalTipeAmount += tipe.total;
            reportText += `${padRight(name, 18)} ${padLeft(tipe.count, 3)} ${padLeft(formatNumber(tipe.total), 18)}\n`;
        });
        reportText += line('-') + `${padRight('  Jumlah', 18)} ${padLeft(totalTipeCount, 3)} ${padLeft(formatNumber(totalTipeAmount), 18)}\n\n`;
    }
    
    if (Object.keys(salesByCategory).length > 0) {
        reportText += 'Sales By Kategory\n' + line('-');
        let totalCatQty = 0, totalCatAmount = 0;
        Object.keys(salesByCategory).sort().forEach(name => {
            const cat = salesByCategory[name];
            totalCatQty += cat.count; totalCatAmount += cat.total;
            reportText += `${padRight(name, 18)} ${padLeft(cat.count, 3)} ${padLeft(formatNumber(cat.total), 18)}\n`;
        });
        reportText += line('-') + `${padRight('  Jumlah', 18)} ${padLeft(totalCatQty, 3)} ${padLeft(formatNumber(totalCatAmount), 18)}\n\n`;
    }

    if (totalDiscItem > 0) {
        reportText += 'RINCIAN DISCOUNT :\n' + line('-');
        Object.keys(discSummary).sort().forEach(name => {
            const disc = discSummary[name];
            reportText += `${padRight(name, 23)} ${padLeft(disc.count, 2)} ${padLeft(formatNumber(disc.total), 13)}\n`;
        });
        reportText += padLeft(line('-'), 42) + `Total Disc. ${padLeft(formatNumber(totalDiscItem), 29)}\n\n`;
    }
    
    const avgCheck = totalTransactions > 0 ? totalSalesGross / totalTransactions : 0;
    reportText += `${padRight('Average Check', 18)} ${padLeft(totalTransactions, 3)} ${padLeft(formatNumber(avgCheck), 18)}\n`;
    
    return reportText;
}

