<?php
// includes/cert_footer_render.php
// Liftek Iraq — Shared bottom-margin (footer) rendering.
//
// WHY THIS FILE EXISTS (single source of truth):
// Both the REAL certificate templates (generate_certificate.php, via
// generate_certificate_pdf.php / export_certificates_zip.php) and the
// admin's Live Preview panel (certificate_settings.php) must render the
// exact same footer band from the exact same code — otherwise a change can
// "look right" in one place and be silently wrong in the other, which is
// exactly what caused repeated wasted iterations before (see
// claude/operating-notes-and-lessons.md — "الإصلاح نجح في المعاينة لكن فشل
// في الـ PDF الحقيقي"). Extracting these functions into one shared,
// require_once'd file makes that class of bug structurally impossible: the
// settings page's preview calls the identical function, not a hand-copied
// look-alike.
//
// Guarded with its own defined() check (same pattern as
// CERT_RENDER_HELPERS_LOADED in generate_certificate.php) so it stays safe
// to require_once from multiple entry points, including the in-process
// include() loop in export_certificates_zip.php which re-executes
// generate_certificate.php's BODY once per certificate but only ever
// *declares* each function once.

if (!defined('CERT_FOOTER_RENDER_LOADED')) {
define('CERT_FOOTER_RENDER_LOADED', true);

/**
 * Returns an image src value safe for both browser HTML and Dompdf PDF.
 *
 * Browser mode : returns htmlspecialchars($webPath) — browser resolves relative paths.
 * PDF mode     : converts the local file to "data:mime;base64,..." — no HTTP from Dompdf.
 *
 * NOTE ON RELOCATION: this function used to live directly inside
 * generate_certificate.php and anchored its project-root path via
 * realpath(dirname(__FILE__)) — i.e. "wherever this function's own file
 * physically sits". Now that this file lives one level down, in
 * includes/, that anchor is realpath(__DIR__ . '/..') instead so the
 * resolved root is still the actual project root (mehok/), not
 * mehok/includes/ — this matters for the path-containment security check
 * below, which would otherwise reject every legitimate path.
 */
function pdfImageSrc(?string $webPath, bool $pdfMode): string
{
    if (empty($webPath)) return '';
    if (!$pdfMode)       return htmlspecialchars($webPath);
    if (str_starts_with($webPath, 'data:')) return $webPath; // already a data URI

    // Resolve to an absolute filesystem path anchored to the project root
    // (one directory above this includes/ file).
    $projectRoot = realpath(__DIR__ . '/..');
    if ($projectRoot === false) return '';

    // Normalise separators before resolving; handles both Unix and Windows paths.
    $normalized = ltrim(str_replace(['/', '\\'], DIRECTORY_SEPARATOR, $webPath), DIRECTORY_SEPARATOR);
    $absPath    = realpath($projectRoot . DIRECTORY_SEPARATOR . $normalized);

    if (!$absPath || !is_file($absPath) || !is_readable($absPath)) return '';

    // SECURITY: strict path containment — the resolved path must be inside the project root.
    if (strncmp($absPath, $projectRoot, strlen($projectRoot)) !== 0) return '';

    $mime = @mime_content_type($absPath);
    if (!$mime || !str_starts_with($mime, 'image/')) return '';

    $bytes = @file_get_contents($absPath);
    if ($bytes === false) return '';

    return 'data:' . $mime . ';base64,' . base64_encode($bytes);
}

/**
 * Renders the admin-uploaded custom footer IMAGE instead of the text-line
 * footer — see certificate_settings.php's "Bottom Margin — Display Mode"
 * (Footer_Mode = 'image'). Pinned into the EXACT same physical footer slot
 * every certificate category already reserves (position:absolute; bottom:0;
 * full content width; 40mm tall — see renderCertFooterBand() below for why
 * that height and why bottom:0 is never a negative offset) so switching
 * modes never changes any other measurement on the page and applies
 * identically across every template (Training/Appliance/LLG/Misc all share
 * this one function).
 *
 * object-fit:contain reads the uploaded image's OWN true pixel proportions
 * and scales it down to fit inside that slot without ever stretching,
 * squashing, or cropping it — this is what keeps it looking exactly like
 * the design the admin uploaded, whatever its real width/height is, rather
 * than forcing every future image into one hardcoded size.
 */
function renderCertFooterImage(string $webPath, bool $pdfMode): void {
    $src = pdfImageSrc($webPath, $pdfMode);
    if ($src === '') return; // fails safe — never a broken-image icon on a legal certificate
    ?>
    <div style="position:absolute; bottom:0; left:0; right:0; height:40mm; padding:0; box-sizing:border-box; overflow:hidden; display:flex; align-items:center; justify-content:center;">
        <img src="<?= $src; ?>" style="max-width:100%; max-height:100%; object-fit:contain; display:block;">
    </div>
    <?php
}

/**
 * Renders the fixed footer band (bottom margin) — a genuinely blank space
 * by default. Split into THREE independent zones on one row, matching a
 * real printed certificate's footer layout: right = Arabic (RTL), center =
 * a short note (either language), left = English (LTR) — set per-line via
 * certificate_settings.php's "Side" selector. Each line still keeps its
 * own size/color/alignment/bold within its zone.
 *
 * BUG FIX HISTORY / WHY A <table>, NOT flexbox: earlier layouts in this
 * project that used flexbox with justify-content for horizontal
 * distribution repeatedly rendered wrong inside Dompdf (items collapsed
 * together near one edge instead of spreading out — confirmed by the
 * client via screenshot, in at least 6 separate places across this file).
 * A plain HTML <table> with three <td> cells is the one pattern proven
 * reliable in this exact codebase for this exact kind of side-by-side
 * layout, so the 3-zone footer uses it too rather than flex:1 columns.
 *
 * $settings carries Footer_Mode/Footer_Image_Path (see $certSettings at the
 * top of generate_certificate.php) — when the admin has switched to
 * "Custom Image" mode AND actually uploaded one, the text-line footer is
 * skipped entirely and renderCertFooterImage() takes over instead
 * ("تعطيل الهامش السفلي ورفع صورة مكانه"). Falls back to the text-line
 * footer if image mode is chosen but no image has been uploaded yet — a
 * certificate must never render with a silently empty margin just because
 * of an incomplete admin setup.
 */
function renderCertFooterBand(array $footerTexts, array $settings = []): void {
    global $pdf_mode;
    $pdf_mode = $pdf_mode ?? false; // defensive default when called from a
                                     // context that never set this global
                                     // (e.g. certificate_settings.php's
                                     // browser-only Live Preview panel).

    $footerMode = $settings['Footer_Mode'] ?? 'text';
    $footerImagePath = $settings['Footer_Image_Path'] ?? null;

    if ($footerMode === 'image' && !empty($footerImagePath)) {
        renderCertFooterImage($footerImagePath, $pdf_mode);
        return;
    }

    if (empty($footerTexts)) return;

    $leftLines   = array_filter($footerTexts, fn($l) => ($l['Column_Side'] ?? 'left') === 'left');
    $centerLines = array_filter($footerTexts, fn($l) => ($l['Column_Side'] ?? 'left') === 'center');
    $rightLines  = array_filter($footerTexts, fn($l) => ($l['Column_Side'] ?? 'left') === 'right');

    // BUG FIX: each line's own Text_Align (an admin-configurable field,
    // meant for WITHIN-line alignment of a wrapped paragraph) defaults to
    // 'left' when not explicitly set. That default was being applied
    // literally even for lines placed in the RIGHT column — so a right-
    // column line with no explicit alignment rendered flush against the
    // LEFT edge of its own zone, which visually sits nowhere near the true
    // right margin ("الهامش العربي بالمنتصف بدل اليمين"). $forcedAlign makes
    // each zone default to hugging its own true edge (left zone -> left,
    // right zone -> right, center zone -> center) UNLESS the admin
    // explicitly chose center/justify on that specific line, which is
    // always respected.
    $renderLine = function (array $line, string $forcedAlign) use ($pdf_mode): void {
        $fontSize = (int) ($line['Font_Size'] ?? 9);
        if ($fontSize < 5 || $fontSize > 20) $fontSize = 9;
        $configuredAlign = $line['Text_Align'] ?? '';
        $align = in_array($configuredAlign, ['center', 'justify'], true) ? $configuredAlign : $forcedAlign;
        $weight = ($line['Font_Weight'] ?? '') === 'bold' ? 'bold' : 'normal';
        // Auto-detect Arabic-script text (regardless of which zone it's
        // in) so the .rtl-text font-face rule (see <head>, only active once
        // an Arabic font is available) is applied wherever it's actually
        // needed, not just on lines an admin manually marked "right".
        // preg_match on the Arabic Unicode block is a safe, purely
        // additive check — no effect on pure-Latin lines.
        $rawText   = $line['Text_Content'] ?? '';
        $hasArabic = (bool) preg_match('/[\x{0600}-\x{06FF}]/u', $rawText);
        $rtlClass  = $hasArabic ? 'rtl-text' : '';
        // PDF-ONLY: Dompdf can't shape/reorder Arabic itself (see
        // includes/arabic_pdf_shaper.php) — pre-shape it here before
        // escaping. The browser View (and the settings-page Live Preview,
        // which always calls this with $pdf_mode=false) is untouched.
        $displayText = ($hasArabic && $pdf_mode && function_exists('arabicShapeForPdf'))
            ? arabicShapeForPdf($rawText)
            : $rawText;
        ?>
        <div class="<?= $rtlClass; ?>" style="font-size: <?= $fontSize; ?>px; line-height: 1.3; text-align: <?= $align; ?>; color: <?= htmlspecialchars($line['Text_Color']); ?>; font-weight: <?= $weight; ?>;">
            <?= nl2br(htmlspecialchars($displayText)); ?>
        </div>
        <?php
    };
    ?>
    <!-- Pinned to the true physical bottom of the page (position:absolute;
         bottom:0), matching a real printed certificate's fixed footer band —
         this is intentional and must stay pinned regardless of how short the
         page content is ("يجب ان يكون ثابت مكانه اسفل الصفحة"). The caller
         reserves a matching bottom margin on its content wrapper so normal
         content never reaches down into this space; see the margin note on
         each cert-paper's inner wrapper in generate_certificate.php. -->
    <div style="position:absolute; bottom:0; left:0; right:0; min-height:16mm; max-height:22mm; overflow:hidden; padding: 0 15mm; box-sizing:border-box;">
        <table style="width:100%; border-collapse:collapse;" cellpadding="0" cellspacing="0">
            <tr>
                <?php if (!empty($centerLines)): ?>
                    <!-- Center zone actually has content: true 3-way split.
                         33/34/33 so the three widths sum to exactly 100%. -->
                    <td style="width:33.33%; vertical-align:middle; border:none; padding:0 6px 0 0; direction:ltr;">
                        <?php foreach ($leftLines as $line) $renderLine($line, 'left'); ?>
                    </td>
                    <td style="width:33.34%; vertical-align:middle; border:none; padding:0 6px;">
                        <?php foreach ($centerLines as $line) $renderLine($line, 'center'); ?>
                    </td>
                    <td style="width:33.33%; vertical-align:middle; border:none; padding:0 0 0 6px; direction:rtl;" dir="rtl">
                        <?php foreach ($rightLines as $line) $renderLine($line, 'right'); ?>
                    </td>
                <?php else: ?>
                    <!-- No center-zone line configured (the common case for
                         every certificate until an admin actually adds one,
                         including every certificate that already existed
                         before this 3-zone layout shipped) — fall back to
                         the original 50/50 two-column split rather than
                         leaving an empty middle third that would just
                         needlessly narrow the left/right text and risk more
                         line-wrapping than before. This is what keeps adding
                         the "Center" zone purely additive: nothing already
                         configured changes width until a center line is
                         actually added. -->
                    <td style="width:50%; vertical-align:middle; border:none; padding:0 6px 0 0; direction:ltr;">
                        <?php foreach ($leftLines as $line) $renderLine($line, 'left'); ?>
                    </td>
                    <td style="width:50%; vertical-align:middle; border:none; padding:0 0 0 6px; direction:rtl;" dir="rtl">
                        <?php foreach ($rightLines as $line) $renderLine($line, 'right'); ?>
                    </td>
                <?php endif; ?>
            </tr>
        </table>
    </div>
    <?php
}

} // end if (!defined('CERT_FOOTER_RENDER_LOADED'))
