<?php
/**
 * RsPdfReport — FPDF subclass for warm-palette tabular reports.
 * Uses Roboto Condensed (Regular + Bold) from /fonts/fpdf/.
 */
class RsPdfReport extends FPDF
{
    /** Light neutral palette — soft charcoal on slate, no brown/tan */
    private $cInk       = [51,  65,  85];  // #334155 slate-700
    private $cMuted     = [100, 116, 139]; // #64748B slate-500
    private $cAccent    = [122, 139, 161]; // #7A8BA1 dusty blue-gray
    private $cLine      = [226, 232, 240]; // #E2E8F0 slate-200
    private $cHeaderBg  = [241, 245, 249]; // #F1F5F9 slate-100
    private $cFooterBg  = [226, 232, 240]; // #E2E8F0 slate-200
    private $cPositive  = [122, 158, 126]; // #7A9E7E light sage
    private $cNegative  = [196, 133, 121]; // #C48579 soft rose

    private $reportTitle    = '';
    private $reportSubtitle = '';
    /** @var array<int,array{label:string,width:float,align:string,type:string}> */
    private $columns = [];

    public function __construct($orientation = 'P', $unit = 'mm', $size = 'A4')
    {
        parent::__construct($orientation, $unit, $size);
        // FPDF requires AddFont before SetFont for non-core fonts
        $this->AddFont('Roboto_Condensed-Regular', '', 'Roboto_Condensed-Regular.php');
        $this->AddFont('Roboto_Condensed-Bold',    '', 'Roboto_Condensed-Bold.php');
        $this->SetMargins(10, 22, 10);
        $this->SetAutoPageBreak(true, 15);
    }

    public function setReportMeta(string $title, string $subtitle = ''): void
    {
        // Sanitize once at store-time so every downstream Cell() call gets Latin-1-safe text.
        // Fixes `Â·` (double-encoded U+00B7) appearing in the printed title/subtitle.
        $this->reportTitle    = $this->safe($title);
        $this->reportSubtitle = $this->safe($subtitle);
        $this->SetTitle($this->reportTitle);
        $this->SetAuthor('RS Flow');
    }

    public function setColumns(array $columns): void
    {
        // Normalize + scale widths so they fit the page width. Widths in the spec are relative units.
        $usable = $this->GetPageWidth() - 20; // 10mm margins
        $totalW = 0;
        foreach ($columns as $c) $totalW += (float)($c['width'] ?? 20);
        $scale = $totalW > 0 ? ($usable / $totalW) : 1;

        $out = [];
        foreach ($columns as $c) {
            $out[] = [
                'label' => (string)($c['label'] ?? ''),
                'width' => (float)($c['width'] ?? 20) * $scale,
                'align' => (string)($c['align'] ?? 'L'),
                'type'  => (string)($c['type']  ?? 'string'),
            ];
        }
        $this->columns = $out;
    }

    /* ── Header (runs on every page) ───────────────────────────────────── */
    function Header(): void
    {
        $this->SetFont('Roboto_Condensed-Bold', '', 14);
        $this->SetTextColor(...$this->cInk);
        $this->Cell(0, 8, $this->reportTitle, 0, 1, 'L');
        if ($this->reportSubtitle !== '') {
            $this->SetFont('Roboto_Condensed-Regular', '', 9);
            $this->SetTextColor(...$this->cMuted);
            $this->Cell(0, 5, $this->reportSubtitle, 0, 1, 'L');
        }
        $this->SetDrawColor(...$this->cAccent);
        $this->SetLineWidth(0.6);
        $this->Line($this->lMargin, $this->GetY() + 1, $this->GetPageWidth() - $this->rMargin, $this->GetY() + 1);
        $this->SetLineWidth(0.1);
        $this->Ln(4);
        // Re-draw table header on subsequent pages if columns are known
        if (!empty($this->columns) && $this->PageNo() > 1) $this->drawTableHeader();
    }

    /* ── Footer with page number ───────────────────────────────────────── */
    function Footer(): void
    {
        $this->SetY(-12);
        $this->SetFont('Roboto_Condensed-Regular', '', 8);
        $this->SetTextColor(...$this->cMuted);
        $this->Cell(0, 5, 'Generated ' . date('d M Y H:i') . ' by RS Flow', 0, 0, 'L');
        $this->Cell(0, 5, 'Page ' . $this->PageNo() . ' of {nb}', 0, 0, 'R');
    }

    /* ── Table drawing ────────────────────────────────────────────────── */
    public function drawTableHeader(): void
    {
        $this->SetFont('Roboto_Condensed-Bold', '', 9);
        $this->SetFillColor(...$this->cHeaderBg);
        $this->SetTextColor(...$this->cInk);
        $this->SetDrawColor(...$this->cLine);
        foreach ($this->columns as $c) {
            $this->Cell($c['width'], 7, $this->safe($c['label']), 'TB', 0, $c['align'], true);
        }
        $this->Ln();
    }

    public function drawRow(array $values): void
    {
        // Auto page-break: if we're within 12mm of the bottom, add a new page
        if ($this->GetY() > $this->GetPageHeight() - 20) {
            $this->AddPage();
            $this->drawTableHeader();
        }

        $this->SetFont('Roboto_Condensed-Regular', '', 8.5);
        $this->SetTextColor(...$this->cInk);
        $this->SetDrawColor(...$this->cLine);

        foreach ($this->columns as $i => $c) {
            $raw = $values[$i] ?? '';
            $text = $this->formatCell($raw, $c['type']);
            if ($c['type'] === 'money' && is_numeric($raw)) {
                $this->SetTextColor(...((float)$raw >= 0 ? $this->cInk : $this->cNegative));
            } else {
                $this->SetTextColor(...$this->cInk);
            }
            $this->Cell($c['width'], 5.5, $this->safe($text), 'B', 0, $c['align']);
        }
        $this->Ln();
    }

    public function drawFooter(string $label, array $values): void
    {
        $this->SetFont('Roboto_Condensed-Bold', '', 9);
        $this->SetFillColor(...$this->cFooterBg);
        $this->SetTextColor(...$this->cInk);
        foreach ($this->columns as $i => $c) {
            if ($i === 0) {
                $this->Cell($c['width'], 6.5, $this->safe($label), 'T', 0, 'L', true);
            } else {
                $raw = $values[$i] ?? '';
                $text = $this->formatCell($raw, $c['type']);
                $this->Cell($c['width'], 6.5, $this->safe($text), 'T', 0, $c['align'], true);
            }
        }
        $this->Ln();
    }

    private function formatCell($v, string $type): string
    {
        if ($v === null || $v === '') return '';
        if ($type === 'money') {
            if (!is_numeric($v)) return (string)$v;
            $f = (float)$v;
            return number_format(abs($f)) . ($f < 0 ? ' -' : '');
        }
        if ($type === 'date') {
            $t = strtotime((string)$v);
            return $t ? date('Y-m-d', $t) : (string)$v;
        }
        return (string)$v;
    }

    /** FPDF is Latin-1; convert UTF-8 → Latin-1 and downgrade the few chars that Latin-1 can't represent. */
    private function safe($s): string
    {
        $s = (string)$s;
        // Downgrade only the chars ISO-8859-1 can't hold. Middle dot (U+00B7 = 0xB7) and × (U+00D7 = 0xD7)
        // both exist in Latin-1, so they survive the iconv step.
        $s = strtr($s, [
            "\u{2013}" => '-', "\u{2014}" => '-',   // en/em dash
            "\u{2018}" => "'", "\u{2019}" => "'",   // curly quotes
            "\u{201C}" => '"', "\u{201D}" => '"',
            "\u{2026}" => '...',                     // ellipsis
            "\u{2212}" => '-',                       // math minus
        ]);
        return @iconv('UTF-8', 'ISO-8859-1//TRANSLIT//IGNORE', $s) ?: $s;
    }
}
