<?php
namespace App\Services;

use App\Core\Auth;
use App\Core\Config;
use App\Core\Dates;
use App\Core\Num;
use App\Core\Response;
use App\Core\Settings;

/**
 * Pusat ekspor: Excel (XLSX), CSV, PDF, dan HTML siap cetak.
 * Semua ekspor menghormati filter dan pilihan kolom yang sedang aktif.
 */
class ExportService
{
    /**
     * @param string $format xlsx|csv|pdf|print
     * @param array  $meta   ['judul','subjudul','periode','tanggal_lapor','filter'=>array,'metode','orientasi','nama_berkas']
     * @param array  $columns [['label','key','type','width'], ...]
     * @param array  $rows
     * @param array  $total
     */
    public static function send(string $format, array $meta, array $columns, array $rows, array $total = []): void
    {
        $nama = self::fileName($meta['nama_berkas'] ?? ($meta['judul'] ?? 'laporan'));
        switch (strtolower($format)) {
            case 'csv':
                $csv = CsvWriter::build($columns, $rows, [
                    'total' => $total,
                    'prefix_lines' => self::prefixLines($meta),
                ]);
                Response::sendString($csv, $nama . '.csv', 'text/csv; charset=utf-8');
                return;

            case 'pdf':
                $pdf = self::buildPdf($meta, $columns, $rows, $total);
                Response::sendString($pdf, $nama . '.pdf', 'application/pdf');
                return;

            case 'print':
                echo self::buildPrintHtml($meta, $columns, $rows, $total);
                exit;

            case 'xlsx':
            default:
                $w = new ExcelWriter();
                $w->setTitle($meta['judul'] ?? 'Laporan');
                $w->addSheet(mb_substr($meta['sheet'] ?? ($meta['judul'] ?? 'Laporan'), 0, 31), $columns, $rows, [
                    'judul' => $meta['judul'] ?? 'Laporan',
                    'subjudul' => self::prefixLines($meta),
                    'total' => $total,
                ]);
                $tmp = rtrim((string)(Config::get('paths.tmp') ?: sys_get_temp_dir()), '/') . '/' . $nama . '_' . bin2hex(random_bytes(4)) . '.xlsx';
                $w->save($tmp);
                Response::download($tmp, $nama . '.xlsx',
                    'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', true);
                return;
        }
    }

    public static function prefixLines(array $meta): array
    {
        $lines = [];
        $lines[] = Settings::str('umum.nama_perusahaan', 'PT Roto-Rooter Indonesia');
        if (!empty($meta['subjudul']))      $lines[] = (string)$meta['subjudul'];
        if (!empty($meta['periode']))       $lines[] = 'Periode: ' . $meta['periode'];
        if (!empty($meta['tanggal_lapor'])) $lines[] = 'Tanggal Pelaporan: ' . $meta['tanggal_lapor'];
        if (!empty($meta['metode']))        $lines[] = 'Metode: ' . $meta['metode'];
        $f = array_filter((array)($meta['filter'] ?? []));
        if ($f) {
            $parts = [];
            foreach ($f as $k => $v) $parts[] = $k . ': ' . $v;
            $lines[] = 'Filter: ' . implode('  |  ', $parts);
        }
        $lines[] = 'Dibuat oleh: ' . (Auth::check() ? Auth::name() : 'Sistem') . '  |  Dicetak: ' . Dates::fmtDateTime(Dates::now());
        return $lines;
    }

    public static function buildPdf(array $meta, array $columns, array $rows, array $total = []): string
    {
        $orient = ($meta['orientasi'] ?? null) ?: (count($columns) > 6 ? 'landscape' : 'portrait');
        $p = new PdfWriter($orient, $meta['ukuran'] ?? 'A4');
        $p->setHeader([
            'perusahaan'    => Settings::str('umum.nama_perusahaan', 'PT Roto-Rooter Indonesia'),
            'judul'         => $meta['judul'] ?? 'Laporan',
            'subjudul'      => $meta['subjudul'] ?? null,
            'periode'       => $meta['periode'] ?? null,
            'tanggal_lapor' => $meta['tanggal_lapor'] ?? null,
            'metode'        => $meta['metode'] ?? null,
            'filter'        => $meta['filter'] ?? [],
            'dibuat_oleh'   => Auth::check() ? Auth::name() : 'Sistem',
        ]);

        // Lebar proporsional kolom
        $cols = [];
        foreach ($columns as $c) {
            $type = (string)($c['type'] ?? 'text');
            $w = (float)($c['pdf_width'] ?? 0);
            if ($w <= 0) {
                $w = match ($type) { 'money' => 1.3, 'date' => 0.9, 'int' => 0.7, 'dec' => 0.9, 'pct' => 0.8, default => 1.6 };
                $len = mb_strlen((string)($c['label'] ?? ''));
                if ($type === 'text' && $len > 18) $w = 2.2;
            }
            $cols[] = ['label' => $c['label'] ?? '', 'key' => $c['key'] ?? '', 'type' => $type, 'width' => $w];
        }
        $p->setColumns($cols);

        if (Settings::bool('laporan.tampilkan_tanda_tangan', true) && ($meta['tanda_tangan'] ?? true)) {
            $p->setSignature($meta['blok_tanda_tangan'] ?? [
                ['peran' => 'Dibuat oleh,', 'nama' => Auth::check() ? Auth::name() : '(..................................)',
                 'jabatan' => Settings::str('laporan.pejabat_pemeriksa', 'Staff Finance AR')],
                ['peran' => 'Disetujui oleh,', 'nama' => '(..................................)',
                 'jabatan' => Settings::str('laporan.pejabat_penandatangan', 'Manager Finance')],
            ]);
        }

        $p->start();
        if (!empty($meta['kpi'])) $p->kpiBoxes($meta['kpi']);
        if (!empty($meta['catatan'])) { $p->paragraph((string)$meta['catatan'], 'I', 7.5, [110, 110, 110]); $p->spacer(4); }

        $groupKey = $meta['group_key'] ?? null;
        $lastGroup = null;
        foreach ($rows as $r) {
            if ($groupKey && isset($r[$groupKey]) && $r[$groupKey] !== $lastGroup) {
                $lastGroup = $r[$groupKey];
                $p->groupHeading((string)$lastGroup);
            }
            if (!empty($r['_subtotal'])) { $p->subtotal($r); continue; }
            $p->row($r);
        }
        if ($total) $p->grandTotal($total);
        if (!$rows) $p->paragraph('Tidak ada data yang sesuai dengan filter yang dipilih.', 'I', 8, [130, 130, 130]);

        return $p->render();
    }

    public static function buildPrintHtml(array $meta, array $columns, array $rows, array $total = []): string
    {
        $judul = e($meta['judul'] ?? 'Laporan');
        $perusahaan = e(Settings::str('umum.nama_perusahaan', 'PT Roto-Rooter Indonesia'));
        $h = '<!DOCTYPE html><html lang="id"><head><meta charset="utf-8"><title>' . $judul . '</title>'
           . '<style>
             *{box-sizing:border-box}
             body{font-family:"Segoe UI",Arial,sans-serif;font-size:11px;color:#222;margin:18px}
             h1{font-size:16px;margin:0 0 2px;color:#1f3864}
             h2{font-size:13px;margin:0 0 6px;font-weight:600}
             .meta{font-size:10px;color:#666;margin-bottom:10px;line-height:1.6}
             table{width:100%;border-collapse:collapse;margin-top:8px}
             th{background:#1f3864;color:#fff;padding:6px 5px;text-align:left;font-size:10px;border:1px solid #1f3864}
             td{padding:4px 5px;border:1px solid #d7d7d7;font-size:10px}
             tr:nth-child(even) td{background:#fafbfd}
             .num{text-align:right;font-variant-numeric:tabular-nums}
             .ctr{text-align:center}
             .neg{color:#c00}
             tfoot td{background:#dce6f1;font-weight:700;border-top:2px solid #1f3864}
             .ttd{margin-top:36px;display:flex;gap:48px}
             .ttd div{flex:1;font-size:10px}
             .ttd .line{margin-top:52px;border-top:1px solid #888;padding-top:4px}
             @media print{.noprint{display:none} body{margin:8mm}}
             .noprint{margin-bottom:12px}
             button{padding:7px 14px;font-size:12px;border:1px solid #1f3864;background:#1f3864;color:#fff;border-radius:5px;cursor:pointer}
             button.alt{background:#fff;color:#1f3864}
             </style></head><body>'
           . '<div class="noprint"><button onclick="window.print()">Cetak Halaman Ini</button> '
           . '<button class="alt" onclick="window.close()">Tutup</button></div>'
           . '<h1>' . $perusahaan . '</h1><h2>' . $judul . '</h2><div class="meta">';
        foreach (self::prefixLines($meta) as $i => $line) {
            if ($i === 0) continue;
            $h .= e($line) . '<br>';
        }
        $h .= '</div><table><thead><tr>';
        foreach ($columns as $c) {
            $type = (string)($c['type'] ?? 'text');
            $cls = in_array($type, ['money', 'int', 'dec', 'pct'], true) ? ' class="num"' : ($type === 'date' ? ' class="ctr"' : '');
            $h .= '<th' . $cls . '>' . e($c['label'] ?? '') . '</th>';
        }
        $h .= '</tr></thead><tbody>';
        foreach ($rows as $r) {
            $h .= '<tr>';
            foreach ($columns as $c) {
                $type = (string)($c['type'] ?? 'text');
                $v = $r[$c['key'] ?? ''] ?? null;
                $txt = PdfWriter::formatValue($v, $type);
                $cls = in_array($type, ['money', 'int', 'dec', 'pct'], true) ? 'num' : ($type === 'date' ? 'ctr' : '');
                if (in_array($type, ['money', 'dec'], true) && (float)Num::parse((string)$v) < 0) $cls .= ' neg';
                $h .= '<td' . ($cls ? ' class="' . $cls . '"' : '') . '>' . e($txt) . '</td>';
            }
            $h .= '</tr>';
        }
        $h .= '</tbody>';
        if ($total) {
            $h .= '<tfoot><tr>';
            foreach ($columns as $i => $c) {
                $key = $c['key'] ?? '';
                $type = (string)($c['type'] ?? 'text');
                $v = array_key_exists($key, $total) ? $total[$key] : ($i === 0 ? 'TOTAL' : '');
                $cls = in_array($type, ['money', 'int', 'dec', 'pct'], true) ? 'num' : '';
                $txt = ($i === 0 && $v === 'TOTAL') ? 'TOTAL' : PdfWriter::formatValue($v, $type);
                $h .= '<td' . ($cls ? ' class="' . $cls . '"' : '') . '>' . e($txt) . '</td>';
            }
            $h .= '</tr></tfoot>';
        }
        $h .= '</table>';
        if (Settings::bool('laporan.tampilkan_tanda_tangan', true)) {
            $h .= '<div class="ttd"><div>Dibuat oleh,<div class="line">' . e(Auth::check() ? Auth::name() : '')
               . '<br><span style="color:#888">' . e(Settings::str('laporan.pejabat_pemeriksa', '')) . '</span></div></div>'
               . '<div>Disetujui oleh,<div class="line">(..................................)<br><span style="color:#888">'
               . e(Settings::str('laporan.pejabat_penandatangan', '')) . '</span></div></div></div>';
        }
        $h .= '<script>window.addEventListener("load",function(){setTimeout(function(){window.print()},400)})</script>';
        return $h . '</body></html>';
    }

    public static function fileName(string $base): string
    {
        $s = preg_replace('/[^A-Za-z0-9]+/', '_', $base) ?? 'laporan';
        return trim(mb_substr($s, 0, 60), '_') . '_' . date('Ymd_His');
    }

    /** Membuat berkas Excel berisi baris import yang gagal beserta pesan kesalahannya. */
    public static function rejectedRows(int $batchId): void
    {
        $db = \App\Core\Database::i();
        $batch = $db->one('SELECT * FROM import_batches WHERE id = :id', ['id' => $batchId]);
        if (!$batch) Response::abort(404, 'Batch import tidak ditemukan.');
        $rows = $db->all(
            "SELECT * FROM import_rows WHERE import_batch_id = :id AND status IN ('failed','duplicate','warning') ORDER BY `row_number`",
            ['id' => $batchId]
        );
        // Kumpulkan seluruh kolom asli
        $cols = [];
        foreach ($rows as $r) foreach (array_keys(arr($r['raw_json'])) as $k) $cols[$k] = true;
        $colKeys = array_keys($cols);
        usort($colKeys, fn($a, $b) => ExcelReader::colIndex($a) <=> ExcelReader::colIndex($b));

        $columns = [
            ['label' => 'BARIS', 'key' => '_baris', 'type' => 'int', 'width' => 8],
            ['label' => 'STATUS', 'key' => '_status', 'type' => 'text', 'width' => 14],
            ['label' => 'PESAN KESALAHAN', 'key' => '_pesan', 'type' => 'text', 'width' => 70],
        ];
        foreach ($colKeys as $k) $columns[] = ['label' => 'Kolom ' . $k, 'key' => $k, 'type' => 'text', 'width' => 22];

        $statusLabel = ['failed' => 'GAGAL', 'duplicate' => 'DUPLIKAT', 'warning' => 'PERINGATAN'];
        $data = [];
        foreach ($rows as $r) {
            $raw = arr($r['raw_json']);
            $msgs = array_merge(arr($r['errors_json']), arr($r['warnings_json']));
            $line = ['_baris' => (int)$r['row_number'], '_status' => $statusLabel[$r['status']] ?? $r['status'],
                     '_pesan' => implode(' | ', $msgs)];
            foreach ($colKeys as $k) $line[$k] = $raw[$k] ?? null;
            $data[] = $line;
        }

        self::send('xlsx', [
            'judul' => 'BARIS IMPORT YANG PERLU DIPERBAIKI',
            'subjudul' => 'Batch ' . $batch['batch_no'] . ' — berkas ' . $batch['file_name'] . ' — sheet ' . $batch['sheet_name'],
            'sheet' => 'Baris Bermasalah',
            'nama_berkas' => 'baris_gagal_' . $batch['batch_no'],
        ], $columns, $data);
    }
}
