<?php

namespace Modules\MedDocuments\Services;

/**
 * Dynamic watermarking with viewer info (spec §8).
 *
 * Approach (pragmatic, per docs/audit/REUSE-MAP.md §8):
 *  - Images  → GD overlay: a diagonal, semi-transparent repeated stamp of the
 *              viewer name + datetime rendered directly onto the pixels, so the
 *              served bytes are watermarked (not just CSS). Requires ext-gd.
 *  - PDFs    → stamped with mPDF (\Mpdf\Mpdf, already bundled + used by the ERP
 *              for all PDFs). mPDF's FpdiTrait imports every source page and we
 *              overlay a rotated, faint watermark on each. If mPDF/GD is
 *              unavailable, callers fall back to the HTML viewer page whose CSS
 *              overlay carries the same watermark text (see file.print / share
 *              views).
 *
 * LIMITATION (documented in README): the image/PDF pixel/vector watermark is a
 * deterrent, not DRM — a determined user with the raw-download permission
 * (meddoc.download_original) can always obtain the unmarked file, and screen
 * capture defeats any on-screen watermark. Very large files / unusual PDFs may
 * fail to re-render; those degrade to the CSS-overlay HTML viewer.
 */
class Watermarker
{
    /**
     * Watermark raw image bytes with the given text. Returns the re-encoded
     * (PNG) bytes, or the original bytes unchanged if GD is missing or the
     * image can't be decoded.
     */
    public function image(string $bytes, string $text): string
    {
        if (! function_exists('imagecreatefromstring')) {
            return $bytes;
        }

        $src = @imagecreatefromstring($bytes);
        if ($src === false) {
            return $bytes;
        }

        $w = imagesx($src);
        $h = imagesy($src);

        imagealphablending($src, true);
        imagesavealpha($src, true);

        // Semi-transparent white text with a faint dark shadow for contrast on
        // any background. GD alpha: 0 = opaque, 127 = fully transparent.
        $fg     = imagecolorallocatealpha($src, 255, 255, 255, 95);
        $shadow = imagecolorallocatealpha($src, 0, 0, 0, 105);

        $font  = 5; // largest built-in GD font (no TTF dependency)
        $charW = imagefontwidth($font);
        $charH = imagefontheight($font);
        $textW = $charW * max(strlen($text), 1);

        // Tile the stamp diagonally across the whole image.
        $stepX = max($textW + 120, 220);
        $stepY = max($charH + 90, 130);

        for ($y = -$h; $y < $h * 2; $y += $stepY) {
            for ($x = -$w; $x < $w * 2; $x += $stepX) {
                imagestring($src, $font, $x + 1, $y + 1, $text, $shadow);
                imagestring($src, $font, $x, $y, $text, $fg);
            }
        }

        ob_start();
        imagepng($src);
        $out = ob_get_clean();
        imagedestroy($src);

        return $out !== false && $out !== '' ? $out : $bytes;
    }

    /**
     * Stamp every page of a source PDF (given as raw bytes) with the watermark
     * text using mPDF. Returns the stamped PDF bytes, or null if stamping is
     * not possible (mPDF missing / import failure) so the caller can fall back
     * to the CSS-overlay HTML viewer.
     */
    public function pdf(string $bytes, string $text): ?string
    {
        if (! class_exists(\Mpdf\Mpdf::class)) {
            return null;
        }

        $tmpDir = storage_path('app/meddocs/_tmp');
        if (! is_dir($tmpDir)) {
            @mkdir($tmpDir, 0775, true);
        }

        $srcFile = $tmpDir . '/src_' . uniqid('', true) . '.pdf';

        try {
            file_put_contents($srcFile, $bytes);

            $mpdf = new \Mpdf\Mpdf([
                'tempDir' => $tmpDir,
                'mode'    => 'utf-8',
            ]);

            $mpdf->SetWatermarkText($text);
            $mpdf->showWatermarkText = true;
            $mpdf->watermarkTextAlpha = 0.12;
            $mpdf->watermark_font = 'DejaVuSans';

            $pageCount = $mpdf->setSourceFile($srcFile);
            for ($i = 1; $i <= $pageCount; $i++) {
                $tpl = $mpdf->importPage($i);
                $size = $mpdf->getTemplateSize($tpl);

                $orientation = ($size['width'] > $size['height']) ? 'L' : 'P';
                $mpdf->AddPageByArray([
                    'orientation' => $orientation,
                    'newformat'   => [$size['width'], $size['height']],
                ]);
                $mpdf->useTemplate($tpl);
            }

            $out = $mpdf->Output('', 'S');
        } catch (\Throwable $e) {
            \Log::warning('MedDocuments PDF watermark failed: ' . $e->getMessage());
            $out = null;
        } finally {
            if (is_file($srcFile)) {
                @unlink($srcFile);
            }
        }

        return $out ?: null;
    }

    /**
     * The standard watermark caption: viewer name + timestamp.
     */
    public static function caption(?string $viewerName): string
    {
        $name = trim((string) $viewerName) ?: 'Shared view';

        return $name . '  •  ' . now()->format('Y-m-d H:i');
    }
}
