<?php
declare(strict_types=1);

namespace Core;

use Mpdf\Mpdf;

/**
 * mPDF wrapper. Each visit type (PM, Fuel, Grid, Callout) renders a print-
 * only PHP view and calls Pdf::download() with the captured HTML.
 *
 * Photos embedded by callers should be inline base64 (use ::imgDataUri()).
 * mPDF can also fetch by URL but on WAMP behind PROOT the URL is sometimes
 * not reachable from the PHP process — base64 is portable.
 */
final class Pdf
{
    /**
     * Render HTML to PDF and stream as a download. Exits after streaming.
     */
    public static function download(string $html, string $filename): void
    {
        $mpdf = self::factory();
        $mpdf->WriteHTML($html);
        // mPDF sets Content-Disposition + Content-Type itself.
        $mpdf->Output($filename, \Mpdf\Output\Destination::DOWNLOAD);
        exit;
    }

    /**
     * Render HTML to PDF and stream inline (browser opens it instead of
     * downloading). Useful for "preview" buttons.
     */
    public static function inline(string $html, string $filename): void
    {
        $mpdf = self::factory();
        $mpdf->WriteHTML($html);
        $mpdf->Output($filename, \Mpdf\Output\Destination::INLINE);
        exit;
    }

    /**
     * Resolve a relative storage path to an absolute filesystem path suitable
     * for use in <img src="..."> within mPDF. mPDF reads the file from disk
     * lazily at render time — much more memory-efficient than base64-inlining,
     * which can easily exhaust 128MB on PMs with 50+ photos.
     *
     * Returns NULL if the file is missing.
     */
    public static function imgPath(string $relativePath): ?string
    {
        $rel = ltrim($relativePath, '/\\');
        if (str_starts_with($rel, 'attachments/')) {
            $rel = substr($rel, strlen('attachments/'));
        }
        $abs = STORAGE . DS . 'uploads' . DS . str_replace(['/', '\\'], DS, $rel);
        if (!is_file($abs)) return null;
        // Forward-slash form works on both Windows + *nix and is what mPDF
        // expects when given an absolute path in an <img src=...>.
        return str_replace('\\', '/', $abs);
    }

    /**
     * Legacy alias kept for callers that still embed inline. Avoid for new
     * code — use imgPath() for memory efficiency.
     */
    public static function imgDataUri(string $relativePath): ?string
    {
        $abs = self::imgPath($relativePath);
        if (!$abs) return null;
        $diskPath = str_replace('/', DS, $abs);
        $mime = self::detectMime($diskPath);
        $b64  = base64_encode((string) file_get_contents($diskPath));
        return "data:{$mime};base64,{$b64}";
    }

    private static function factory(): Mpdf
    {
        // Cache dir under storage/ so it survives webroot lockdown.
        $cache = ROOT . DS . 'storage' . DS . 'mpdf-tmp';
        if (!is_dir($cache)) @mkdir($cache, 0775, true);
        return new Mpdf([
            'mode'              => 'utf-8',
            'format'            => 'A4',
            'margin_top'        => 14,
            'margin_bottom'     => 14,
            'margin_left'       => 12,
            'margin_right'      => 12,
            'default_font'      => 'sans-serif',
            'default_font_size' => 10,
            'tempDir'           => $cache,
        ]);
    }

    private static function detectMime(string $path): string
    {
        if (function_exists('finfo_open')) {
            $f = finfo_open(FILEINFO_MIME_TYPE);
            $m = $f ? finfo_file($f, $path) : null;
            if ($m) return (string)$m;
        }
        $ext = strtolower(pathinfo($path, PATHINFO_EXTENSION));
        return match ($ext) {
            'png'         => 'image/png',
            'webp'        => 'image/webp',
            'gif'         => 'image/gif',
            'jpg', 'jpeg' => 'image/jpeg',
            default       => 'image/jpeg',
        };
    }
}
