<?php //Generator
// ==== expects: $parts from assembler (no re-includes here) ====
// keys: wrapper_Start, wrapper_End, headerTemplate, contractHeader, inst, body, footerTemplate, orientation, customImages
ini_set('display_errors', 1);ini_set('display_startup_errors', 1);error_reporting(E_ALL);
$tenantBase = '../../../' . TENANT_URL;
$ENGINES_DIR = $tenantBase . '/engines/pdf_structure';
// Render
// Ensure output dir
$reportsDir = $tenantBase . '/output/reports/' . ($_REQUEST['clientnumber'] ?? '');
if (!is_dir($reportsDir)) {
    @mkdir($reportsDir, 0777, true);
}

$reportImageDefaults = [
    'main_logo'        => 40,
    'client_logo'      => 40,
    'affiliation_logo' => 40
];

$reportImageSettings = $parts['reportImageSettings'] ?? $reportImageDefaults;

$headerImgHeight = (int)($reportImageSettings['main_logo'] ?? 40);
$clientImgHeight = (int)($reportImageSettings['client_logo'] ?? 40);
$aflImgHeight    = (int)($reportImageSettings['affiliation_logo'] ?? 40);

if ($headerImgHeight <= 0) $headerImgHeight = 40;
if ($clientImgHeight <= 0) $clientImgHeight = 40;
if ($aflImgHeight <= 0) $aflImgHeight = 40;
// QR
require "../../packages/phpqrcode/qrlib.php";
$qrPath = $tenantBase . '/images/repQR.png';
QRcode::png(getCompanyDetails('web') . '/preview.php?repnumber=' . ($_REQUEST['repnumber'] ?? ''), $qrPath, 'L', 4, 2);

// Resolve header/footer templates (they are always NAME.php)
$headerHtml = '';
$footerHtml = '';
$tailFooterHtml = '';
$footerMode = strtolower((string)($parts['footerMode'] ?? $parts['footermode'] ?? 'repeat'));
if ($footerMode !== 'tail') {
    $footerMode = 'repeat';
}
if (!empty($parts['headerTemplate'])) {
    $p = $ENGINES_DIR . '/' . $parts['headerTemplate'];
    if (is_file($p)) $headerHtml = file_get_contents($p);
}
if (!empty($parts['footerTemplate'])) {
    $p = $ENGINES_DIR . '/' . $parts['footerTemplate'];
    if (is_file($p)) $footerHtml = file_get_contents($p);
}
if ($footerMode === 'tail') {
    $p = $ENGINES_DIR . '/footer_simple.php';
    $tailFooterHtml = $footerHtml;
    $footerHtml = '';
    if (is_file($p)) {
        $footerHtml = file_get_contents($p);
    }
}


$customerSignature = '';
if (!empty($cx['viewed'])) {
    $customerSignature = 'data:image/png;base64,' . base64_encode($cx['viewed']);
}

// ----- Contractor context + precompute address/logo + AF suppression flag -----
$clientId = isset($_REQUEST['clientnumber']) ? (int)$_REQUEST['clientnumber'] : 0;
$isContract = false;
$contract = null;
$contractAddressHtml = '';
$contractLogoHtml = '';

function enrep_render_title_bar(?string $text, int $widthPx, int $radius = 24, int $heightPx = 54): string
{
    $text = trim((string)$text);
    if ($text === '') return '';

    // truncate (unchanged)
    $maxLen = 60;
    if (function_exists('mb_strlen') && function_exists('mb_substr')) {
        if (mb_strlen($text, 'UTF-8') > $maxLen) $text = rtrim(mb_substr($text, 0, $maxLen, 'UTF-8')) . '...';
    } else {
        if (strlen($text) > $maxLen) $text = rtrim(substr($text, 0, $maxLen)) . '...';
    }

    $xmlText = htmlspecialchars($text, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');

    $w = max(120, (int)$widthPx);

    $rWanted = max(0, (int)$radius);
    // Force height big enough to render that radius properly
    $hMinForRadius = ($rWanted * 2) + 10;
    $h = max(40, (int)$heightPx, $hMinForRadius);

    $r = max(0, min($rWanted, (int)floor(min($w, $h) / 2)));

    $svg = <<<SVG
<svg xmlns="http://www.w3.org/2000/svg" width="{$w}" height="{$h}" viewBox="0 0 {$w} {$h}">
  <rect x="0" y="0" width="{$w}" height="{$h}" rx="{$r}" ry="{$r}" fill="#252f38"/>
  <rect x="0" y="{$r}" width="{$w}" height="{$h}" fill="#252f38"/>
  <text x="50%" y="50%" fill="#FFFFFF" font-family="DejaVu Sans, Arial, sans-serif"
        font-size="22" font-weight="600" dominant-baseline="middle" text-anchor="middle">
    {$xmlText}
  </text>
</svg>
SVG;

    return 'data:image/svg+xml;base64,' . base64_encode($svg);
}




if ($clientId > 0) {
    // single fetch: clientMode + contractor row
    $sql = "SELECT c.clientMode,
                   cc.id,
                   cc.cont_company, cc.cont_company_short,
                   cc.cont_address1, cc.cont_address2, cc.cont_town, cc.cont_county, cc.cont_post,
                   cc.cont_tel, cc.cont_main_email, cc.cont_finance_email, cc.cont_web
            FROM clientdetails c
            LEFT JOIN contract_companies cc ON cc.client_id = c.clientnumber
            WHERE c.clientnumber = ? LIMIT 1";
    $st = $GLOBALS['con']->prepare($sql);
    $st->bind_param('i', $clientId);
    $st->execute();
    $res = $st->get_result();
    if ($row = $res->fetch_assoc()) {
        $isContract = ((int)$row['clientMode'] === 1) && !empty($row['id']);
        if ($isContract) {
            $contract = $row;

            // address (single line) with bold company
            $companyName = '';
            if (!empty($contract['cont_company'])) {
                $companyName = '<strong>' . htmlspecialchars($contract['cont_company'], ENT_QUOTES, 'UTF-8') . '</strong>';
            } elseif (!empty($contract['cont_company_short'])) {
                $companyName = '<strong>' . htmlspecialchars($contract['cont_company_short'], ENT_QUOTES, 'UTF-8') . '</strong>';
            }

            $addrParts = array(
                $companyName,
                !empty($contract['cont_address1']) ? $contract['cont_address1'] : '',
                !empty($contract['cont_address2']) ? $contract['cont_address2'] : '',
                trim((!empty($contract['cont_town']) ? $contract['cont_town'] : '') . ' ' . (!empty($contract['cont_post']) ? $contract['cont_post'] : '')),
                !empty($contract['cont_county']) ? $contract['cont_county'] : '',
            );

            $filtered = array();
            foreach ($addrParts as $p) {
                if ($p !== '' && $p !== null) {
                    // company is already escaped+wrapped
                    if ($p === $companyName) $filtered[] = $p;
                    else $filtered[] = htmlspecialchars($p, ENT_QUOTES, 'UTF-8');
                }
            }
            $contractAddressHtml = implode(', ', $filtered);

            // contractor logo
            $cLogoPath = $tenantBase . '/images/contractorCompany/' . (int)$contract['id'] . '.jpg';
            if (is_file($cLogoPath)) {
                $contractLogoHtml = '<img src="' . $cLogoPath . '" height="70px" />';
            }
        }
    }
    $st->close();
}


// AF images (optional exclude per customImages[form])
$form = $_REQUEST['form'] ?? '';
$excludeImage = 0;
if (!empty($parts['customImages']) && is_array($parts['customImages']) && isset($parts['customImages'][$form])) {
    $excludeImage = (int)$parts['customImages'][$form];
}
for ($i = 1; $i <= 6; $i++) {
    if ($isContract) { // hide all AF images in contractor mode
        $headerHtml = str_replace("[AF{$i}]", '', $headerHtml);
        continue;
    }
    $img = $tenantBase . "/images/company/afl_{$i}.jpg";
    if ($excludeImage === $i) {
        $headerHtml = str_replace("[AF{$i}]", '', $headerHtml);
        continue;
    }
    $headerHtml = str_replace("[AF{$i}]", file_exists($img) ? '<td><img src="' . $img . '" height="' . $aflImgHeight . '" /></td>' : '', $headerHtml);
}

// Data for swaps
$sdata = explode("|", getSurveyorDetails($_REQUEST['repnumber'] ?? '', 'REPDATA'));
$rdata = explode("|", getItemReportDetails($_REQUEST['repnumber'] ?? '', 'REPDATA'));

// Surveyor signature to base64
$base64ImageSrc = '';
$signPath = $tenantBase . '/images/signatures/' . ($sdata[2] ?? '') . '.jpg';
if (file_exists($signPath)) $base64ImageSrc = 'data:image/jpeg;base64,' . base64_encode(file_get_contents($signPath));

// Gary signature to base64
$gary64ImageSrc = '';
$garyPath = $tenantBase . '/images/signatures/2.jpg';
if (file_exists($garyPath)) $gary64ImageSrc = 'data:image/jpeg;base64,' . base64_encode(file_get_contents($garyPath));

// Styles (default generic style.php; swap if you later add per-type)
$styleHtml = '';
$stylePath = $ENGINES_DIR . '/style.php';
if (is_file($stylePath)) $styleHtml = file_get_contents($stylePath);

// ---------- BUILD CONTENT FOR SETTER MODE (no <htmlpageheader> tags) ----------
$header = $headerHtml;                               // header fragment
$footer = $footerHtml;                               // footer fragment
$tailFooter = $tailFooterHtml;                       // final-page footer when footerMode=tail

// First-page extras (under the header, not inside it)
$firstPageExtras = '';
if (!empty($parts['contractHeader'])) $firstPageExtras .= $parts['contractHeader'];
if (!empty($parts['inst']))           $firstPageExtras .= $parts['inst'];

// Body HTML (wrapper + optional first page extras + body + wrapper end)
$mainBody = (string)($parts['body'] ?? '');

/*
 * Remove forced breaks only at the boundary between the first-page extras
 * and the main body. This prevents the first report table being pushed onto
 * page 2 when there is enough space on page 1.
 */
$firstPageExtras = preg_replace(
    '/(?:\s|&nbsp;|<br\s*\/?>)*(?:<pagebreak\s*\/?>|<div[^>]*(?:page-break-after\s*:\s*always|break-after\s*:\s*page)[^>]*>\s*<\/div>)(?:\s|&nbsp;|<br\s*\/?>)*$/i',
    '',
    (string)$firstPageExtras
);

$mainBody = preg_replace(
    '/^(?:\s|&nbsp;|<br\s*\/?>)*(?:<pagebreak\s*\/?>|<div[^>]*(?:page-break-before\s*:\s*always|break-before\s*:\s*page|page-break-after\s*:\s*always|break-after\s*:\s*page)[^>]*>\s*<\/div>)(?:\s|&nbsp;|<br\s*\/?>)*/i',
    '',
    $mainBody
);

/*
 * If the first body element is a table marked as unbreakable,
 * mPDF will move it to the next page. Allow the first table to split,
 * while rows can still avoid splitting.
 */
$mainBody = preg_replace_callback(
    '/<table\b([^>]*)>/i',
    static function ($m) {
        $tag = $m[0];

        if (stripos($tag, 'page-break-inside') !== false) {
            $tag = preg_replace(
                '/page-break-inside\s*:\s*avoid\s*;?/i',
                'page-break-inside:auto;',
                $tag
            );
        } elseif (stripos($tag, 'style=') !== false) {
            $tag = preg_replace(
                '/style=(["\'])(.*?)\1/i',
                'style=$1$2; page-break-inside:auto;$1',
                $tag,
                1
            );
        } else {
            $tag = str_replace('<table', '<table style="page-break-inside:auto;"', $tag);
        }

        return $tag;
    },
    $mainBody,
    1
);

$body  = (string)($parts['wrapper_Start'] ?? '');
$body .= $firstPageExtras;
$body .= $mainBody;
// === Photos at the end (imageMode=1) ===
if (!empty($_REQUEST['imageMode']) && $_REQUEST['imageMode'] === "1") {
    @file_put_contents(
        __DIR__ . "/imagePath.txt",
        "AFTER CALL imageMode=" . $_REQUEST['imageMode'] . '|' . ($cx['itemnumber'] ?? '') . PHP_EOL,
        FILE_APPEND
    );

    $itemNo  = (string)($cx['itemnumber'] ?? '');
    $baseDir = '../../../' . TENANT_URL . '/images/report_images/';
    $PHOTO_RADIUS_PX = 24;

    $imageItems = []; // each: ['path' => string, 'title' => string]
    for ($slot = 1; $slot <= 6; $slot++) {
        $base = $itemNo . '_' . $slot;

        // Prefer described variant first (excluding thumbs)
        $matches = glob($baseDir . $base . '__*.jpg');
        if (!empty($matches)) {
            $matches = array_values(array_filter($matches, static function ($p) {
                return (strpos($p, 'thumb') === false);
            }));
        }

        if (!empty($matches)) {
            $path = $matches[0];

            $fn       = basename($path, '.jpg'); // e.g. 1_1__test-description
            $prefix   = $base . '__';
            $descSlug = (strpos($fn, $prefix) === 0) ? substr($fn, strlen($prefix)) : '';
            $title    = trim(str_replace('-', ' ', $descSlug));

            $imageItems[] = ['path' => $path, 'title' => $title];
            @file_put_contents(__DIR__ . "/imagePath.txt", "SLOT {$slot} DESCRIBED: {$path} | TITLE={$title}" . PHP_EOL, FILE_APPEND);
            continue;
        }

        // Fallback legacy
        $legacy = $baseDir . $base . '.jpg';
        if (file_exists($legacy)) {
            $imageItems[] = ['path' => $legacy, 'title' => ''];
            @file_put_contents(__DIR__ . "/imagePath.txt", "SLOT {$slot} LEGACY: {$legacy}" . PHP_EOL, FILE_APPEND);
        }
    }

    $imgCount = count($imageItems);
    if ($imgCount > 0) {

    // --- fast rounded-corner processor with caching + downscale ---
    if (!function_exists('enrep_process_photo_fast')) {
        /**
         * @param string $src
         * @param int    $radius
         * @param int    $maxH_px
         * @param int    $maxW_px
         * @param bool   $square
         * @param string $cornerMode 'all' (default) or 'bottom' (top corners square)
         * @return string
         */
        function enrep_process_photo_fast(
            string $src,
            int $radius = 24,
            int $maxH_px = 600,
            int $maxW_px = 600,
            bool $square = true,
            string $cornerMode = 'all'
        ): string {
            if (!file_exists($src)) return $src;

            $tenantBase = '../../../' . TENANT_URL;
            $cacheDir   = $tenantBase . '/images/cache';
            if (!is_dir($cacheDir)) @mkdir($cacheDir, 0777, true);

            $cornerMode = ($cornerMode === 'bottom') ? 'bottom' : 'all';

            $mtime = filemtime($src) ?: 0;
            $hash  = md5($src . '|' . $mtime . '|v2|r' . $radius . '|h' . $maxH_px . '|w' . $maxW_px . '|' . ($square ? 'square' : 'fit') . '|cm:' . $cornerMode);
            $dest  = $cacheDir . "/$hash.png";
            if (file_exists($dest)) return $dest;

            // Prefer Imagick
            if (extension_loaded('imagick')) {
                try {
                    $im = new Imagick($src);
                    if (method_exists($im, 'autoOrientImage')) {
                        $im->autoOrientImage();
                    }
                    $im->setImageColorspace(Imagick::COLORSPACE_RGB);
                    $im->setImageAlphaChannel(Imagick::ALPHACHANNEL_SET);

                    $w = $im->getImageWidth();
                    $h = $im->getImageHeight();

                    if ($square) {
                        $side = min($w, $h);
                        $x = (int) floor(($w - $side) / 2);
                        $y = (int) floor(($h - $side) / 2);
                        $im->cropImage($side, $side, $x, $y);
                        $im->setImagePage(0, 0, 0, 0);

                        if ($side !== $maxH_px) {
                            $im->resizeImage($maxH_px, $maxH_px, Imagick::FILTER_LANCZOS, 1, true);
                        }
                    } else {
                        $scale = min($maxW_px / $w, $maxH_px / $h, 1.0);
                        $tw = max(1, (int) floor($w * $scale));
                        $th = max(1, (int) floor($h * $scale));
                        if ($tw !== $w || $th !== $h) {
                            $im->resizeImage($tw, $th, Imagick::FILTER_LANCZOS, 1, true);
                        }
                    }

                    $w = $im->getImageWidth();
                    $h = $im->getImageHeight();
                    $r = max(0, min((int)$radius, (int)floor(min($w, $h) / 2)));

                    $mask = new Imagick();
                    $mask->newImage($w, $h, 'transparent', 'png');

                    $draw = new ImagickDraw();
                    $draw->setFillColor('white');

                    // start with all corners rounded
                    $draw->roundRectangle(0, 0, $w - 1, $h - 1, $r, $r);

                    // if title exists, square the TOP corners by filling a top strip back to opaque
                    if ($cornerMode === 'bottom') {
                        $draw->rectangle(0, 0, $w - 1, $r);
                    }

                    $mask->drawImage($draw);

                    $im->setImageFormat('png');
                    $im->compositeImage($mask, Imagick::COMPOSITE_DSTIN, 0, 0);

                    $im->writeImage($dest);
                    $im->clear(); $im->destroy();
                    $mask->clear(); $mask->destroy();

                    return $dest;
                } catch (Throwable $e) {
                    // fall through
                }
            }

            // GD fallback: square crops only when requested; otherwise preserve the image aspect.
            if (function_exists('imagecreatefromjpeg')) {
                $sourceImage = @imagecreatefromjpeg($src);
                if ($sourceImage !== false) {
                    if (function_exists('exif_read_data')) {
                        $exif = @exif_read_data($src);
                        $orientation = (int)($exif['Orientation'] ?? 1);
                        $rotation = [3 => 180, 6 => -90, 8 => 90][$orientation] ?? 0;
                        if ($rotation !== 0) {
                            $rotated = imagerotate($sourceImage, $rotation, 0);
                            if ($rotated !== false) {
                                imagedestroy($sourceImage);
                                $sourceImage = $rotated;
                            }
                        }
                    }

                    $w = imagesx($sourceImage);
                    $h = imagesy($sourceImage);
                    if ($square) {
                        $side = min($w, $h);
                        $x = (int)floor(($w - $side) / 2);
                        $y = (int)floor(($h - $side) / 2);
                        $targetW = max(1, $maxH_px);
                        $targetH = $targetW;
                    } else {
                        $scale = min($maxW_px / max(1, $w), $maxH_px / max(1, $h), 1.0);
                        $targetW = max(1, (int)floor($w * $scale));
                        $targetH = max(1, (int)floor($h * $scale));
                        $x = 0;
                        $y = 0;
                        $side = null;
                    }

                    $targetImage = imagecreatetruecolor($targetW, $targetH);
                    if ($square) {
                        imagecopyresampled($targetImage, $sourceImage, 0, 0, $x, $y, $targetW, $targetH, $side, $side);
                    } else {
                        imagecopyresampled($targetImage, $sourceImage, 0, 0, 0, 0, $targetW, $targetH, $w, $h);
                    }
                    imagepng($targetImage, $dest);
                    imagedestroy($targetImage);
                    imagedestroy($sourceImage);

                    return $dest;
                }
            }

            return $src;
        }
    }

    // px per mm (approx mPDF CSS pixel ratio)
    $pxPerMm = 96 / 25.4;
    $pageImageWidthMm = 190;
    $columnGapMm = 5;

    if (!function_exists('enrep_fit_photo_mm')) {
        function enrep_fit_photo_mm(string $path, float $maxW_mm, float $maxH_mm): array
        {
            $size = @getimagesize($path);
            $w = max(1, (int)($size[0] ?? 1));
            $h = max(1, (int)($size[1] ?? 1));
            $scale = min($maxW_mm / $w, $maxH_mm / $h);
            return [
                'w' => max(1, round($w * $scale, 2)),
                'h' => max(1, round($h * $scale, 2)),
            ];
        }
    }

    if ($imgCount === 1) {
        $cols = 1;
        $maxH_mm = 220;
    } elseif ($imgCount === 2) {
        $cols = 2;
        $maxH_mm = 200;
    } elseif ($imgCount === 4) {
        $cols = 2;
        $maxH_mm = 105;
    } else {
        $cols = 3;
        $maxH_mm = ($imgCount === 3) ? 150 : 85;
    }

    $cellWidth = floor(100 / max(1, $cols));
    $columnWidthMm = ($cols === 1)
        ? 130
        : (($pageImageWidthMm - ($columnGapMm * ($cols - 1))) / $cols);
    $maxW_px = (int)round($columnWidthMm * $pxPerMm);
    $maxH_px = (int)round($maxH_mm * $pxPerMm);

    $displayItems = [];
    foreach ($imageItems as $idx => $it) {
        $p = $it['path'];
        $rawTitle = trim((string)($it['title'] ?? ''));
        $titleRadius = (int) round($PHOTO_RADIUS_PX * 0.66);
        $titleHeight = max(54, ($titleRadius * 2) + 10);
        $titleSvg = ($rawTitle !== '')
            ? enrep_render_title_bar($rawTitle, 600, $titleRadius, $titleHeight)
            : '';
        $cornerMode = ($rawTitle !== '') ? 'bottom' : 'all';
        $displayPath = enrep_process_photo_fast($p, $PHOTO_RADIUS_PX, $maxH_px, $maxW_px, false, $cornerMode);
        $fit = enrep_fit_photo_mm($displayPath, $columnWidthMm, $maxH_mm);

        $displayItems[] = [
            'path' => $displayPath,
            'title' => $titleSvg,
            'w' => $fit['w'],
            'h' => $fit['h'],
            'estimate' => $fit['h'] + ($titleSvg !== '' ? 9 : 0) + 4,
        ];
    }

    $body .= '<pagebreak />';
    $body .= (string)($injections['beforePhotos'] ?? '');

    if ($imgCount === 1) {
        $item = $displayItems[0];
        $body .= '
            <table width="100%" cellspacing="0" cellpadding="0" style="margin-top:25px; table-layout:fixed;border-collapse:collapse;page-break-inside:avoid;">
                <tr>
                    <td align="center" style="padding:5mm;">' .
            ($item['title'] !== ''
                ? '<div style="width:' . $item['w'] . 'mm; margin:0 auto 2mm auto;">
                       <img src="' . $item['title'] . '" style="width:' . $item['w'] . 'mm; height:auto; display:block; margin:0 auto;">
                   </div>'
                : ''
            ) . '
                        <div style="width:' . $item['w'] . 'mm; margin:0 auto; overflow:hidden;">
                            <img src="' . $item['path'] . '" style="width:' . $item['w'] . 'mm; height:' . $item['h'] . 'mm; display:block; margin:0 auto;">
                        </div>
                    </td>
                </tr>
            </table>';
    } else {
        $columns = array_fill(0, $cols, []);
        $columnHeights = array_fill(0, $cols, 0.0);
        foreach ($displayItems as $item) {
            $target = 0;
            for ($c = 1; $c < $cols; $c++) {
                if ($columnHeights[$c] < $columnHeights[$target]) {
                    $target = $c;
                }
            }
            $columns[$target][] = $item;
            $columnHeights[$target] += $item['estimate'];
        }

        $body .= '
            <table width="100%" cellspacing="0" cellpadding="0" style="margin-top:15px; table-layout:fixed;border-collapse:separate;border-spacing:5mm 5mm;page-break-inside:auto;">
                <tr style="page-break-inside:avoid;">';

        for ($c = 0; $c < $cols; $c++) {
            $body .= '<td align="center" style="width:' . $cellWidth . '%;vertical-align:top;padding:0;page-break-inside:auto;">';
            foreach ($columns[$c] as $itemIndex => $item) {
                if ($itemIndex > 0) {
                    $body .= '<table width="100%" cellspacing="0" cellpadding="0" style="border-collapse:collapse;"><tr><td style="height:8mm; line-height:8mm; font-size:1px;">&nbsp;</td></tr></table>';
                }
                $body .= '<div style="width:100%; margin:0; page-break-inside:avoid;">' .
                    ($item['title'] !== ''
                        ? '<div style="width:' . $item['w'] . 'mm; margin:0 auto 2mm auto;">
                               <img src="' . $item['title'] . '" style="width:' . $item['w'] . 'mm; height:auto; display:block; margin:0 auto;">
                           </div>'
                        : ''
                    ) . '
                    <div style="width:100%; overflow:hidden; text-align:center;">
                        <img src="' . $item['path'] . '" style="width:' . $item['w'] . 'mm; height:' . $item['h'] . 'mm; max-width:100%; display:block; margin:0 auto;">
                    </div>
                </div>';
            }
            $body .= '</td>';
        }

        $body .= '</tr></table>';
    }
}
}


$body .= ($parts['wrapper_End'] ?? '');
// ---------- Contractor override (logo + address) ----------
$clientId = isset($_REQUEST['clientnumber']) ? (int)$_REQUEST['clientnumber'] : 0;
$contract = null;

if ($clientId > 0) {
    // clientMode?
    $stmt = $GLOBALS['con']->prepare("SELECT clientMode FROM clientdetails WHERE clientnumber=? LIMIT 1");
    $stmt->bind_param('i', $clientId);
    $stmt->execute();
    $stmt->bind_result($clientMode);
    $stmt->fetch();
    $stmt->close();

    if ((int)$clientMode === 1) {
        // contractor row
        $stmt = $GLOBALS['con']->prepare("
            SELECT id, cont_company, cont_company_short, cont_address1, cont_address2, cont_town,
                   cont_county, cont_post, cont_tel, cont_main_email, cont_finance_email, cont_web,
                   cont_vatno, cont_compno
            FROM contract_companies
            WHERE client_id=? LIMIT 1
        ");
        $stmt->bind_param('i', $clientId);
        $stmt->execute();
        $res = $stmt->get_result();
        if ($res && $res->num_rows > 0) {
            $contract = $res->fetch_assoc();
        }
        $stmt->close();
    }
}

// Report result for [STAT]
$reportResult = '';
if (!empty($_REQUEST['repnumber']) && isset($GLOBALS['con']) && $GLOBALS['con'] instanceof mysqli) {
    $stmtStat = $GLOBALS['con']->prepare("
        SELECT `result`
        FROM `reportitems`
        WHERE `repnumber` = ?
        LIMIT 1
    ");
    if ($stmtStat) {
        $repNo = (string)$_REQUEST['repnumber'];
        $stmtStat->bind_param('s', $repNo);
        $stmtStat->execute();
        $resStat = $stmtStat->get_result();
        if ($resStat && $rowStat = $resStat->fetch_assoc()) {
            $reportResult = strtoupper(trim((string)($rowStat['result'] ?? '')));
        }
        $stmtStat->close();
    }
}

$statColourMap = [
    'PASS'    => '#007e33',
    'DEFECTS' => '#f80',
    'URGENT'  => '#c00',
    'OBS'     => '#000',
    'PNA'     => '#333',
    'POBS'    => '#007e33',
];
$statColour = $statColourMap[$reportResult] ?? '#999';

// Build a real PNG for [STAT]
$statPath = $tenantBase . '/images/stat_circle.png';

$statSize = max(10, (int)$aflImgHeight);
$im = imagecreatetruecolor($statSize, $statSize);
imagesavealpha($im, true);
imagealphablending($im, false);
$transparent = imagecolorallocatealpha($im, 0, 0, 0, 127);
imagefill($im, 0, 0, $transparent);

$hex = ltrim($statColour, '#');
if (strlen($hex) === 3) {
    $hex = $hex[0].$hex[0].$hex[1].$hex[1].$hex[2].$hex[2];
}
$r = hexdec(substr($hex, 0, 2));
$g = hexdec(substr($hex, 2, 2));
$b = hexdec(substr($hex, 4, 2));
$fill = imagecolorallocate($im, $r, $g, $b);

imagefilledellipse($im, (int)($statSize / 2), (int)($statSize / 2), $statSize - 2, $statSize - 2, $fill);
imagepng($im, $statPath);
imagedestroy($im);

$statHtml = file_exists($statPath)
    ? '<td align="center" valign="middle"><img src="' . $statPath . '" height="' . $aflImgHeight/2 . '" /></td>'
    : '';

// Common replacements (apply to header, footer, and body)
$repl = [
    '[SURVEYOR_NAME]'      => $sdata[0] ?? '',
    '[SURVEYOR_QUAL]'      => $sdata[1] ?? '',
    '[CONTRACT_NO]'        =>$clt[1] ?? '',
    '[SURVEYOR_SIGNITURE]' => $base64ImageSrc,
    '[CUSTOMER_SIGNATURE]' => $customerSignature,
    '[GARY_QUAL]'          => 'IEng MSOE MIPlantE MBES',
    '[GARY_SIGNITURE]'     => $gary64ImageSrc,
    '[REPNO]'              => $rdata[0] ?? '',
    '[EXAM_DATE]'          => $rdata[1] ?? '',
    '[EXAM_PREVDATE]'      => $rdata[2] ?? '',
    '[EXAM_NEXTDATE]'      => $rdata[3] ?? '',
    '[REPORT_DATE]'        => date('d-m-Y'),
    '[REP]'                => $_REQUEST['repnumber'] ?? '',
    '[ITE]'                => $cx['itemnumber'] ?? '',
    '[ADDRESS]'     => ($isContract && $contractAddressHtml !== '') ? $contractAddressHtml : getCompanyDetails('addressLong'),

    '[CONTACT]'            => getCompanyDetails('contact'),
    '[TEL]'                => getCompanyDetails('tel'),
    '[REPORT_PATH]'        => getCompanyDetails('web'),
    '[QR]'                 => '<td><img src="' . $qrPath . '" height="' . $aflImgHeight . '"></td>',
    '[STAT]' => $statHtml,
    '[STATCOLOUR]' =>$statColour,
    '[STATTEXT]' =>$reportResult,
];

// Logos
$companyLogoPath = $tenantBase . '/images/company/logo.jpg';
$clientLogo = $tenantBase . '/images/client/' . $_REQUEST['clientnumber'] . '.jpg';
$repl['[LGO]'] = ($isContract && $contractLogoHtml !== '')
    ? $contractLogoHtml
    : (file_exists($companyLogoPath) ? '<img src="' . $companyLogoPath . '" height="' . $headerImgHeight . '" />' : '');
$repl['[LGOF]'] = ($isContract && $contractLogoHtml !== '')
    ? $contractLogoHtml
    : (file_exists($companyLogoPath) ? '<img src="' . $companyLogoPath . '" height="20px" />' : '');
$repl['[CL1]'] = file_exists($clientLogo) ? '<td align="center"><img src="' . $clientLogo . '" height="' . $clientImgHeight . 'x" style="" /></td>' : '';

// Apply replacements to all pieces
$header = str_replace(array_keys($repl), array_values($repl), $header);
$footer = preg_replace('/(<th\b[^>]*>\s*\[STATTEXT\]\s*)<\/td>/i', '$1</th>', $footer);
$tailFooter = preg_replace('/(<th\b[^>]*>\s*\[STATTEXT\]\s*)<\/td>/i', '$1</th>', $tailFooter);
$footer = str_replace(array_keys($repl), array_values($repl), $footer);
$tailFooter = str_replace(array_keys($repl), array_values($repl), $tailFooter);
$body   = str_replace(array_keys($repl), array_values($repl), $body);

// ---------- FILE DEST ----------
if (($_REQUEST['mode'] ?? '') === "preview") {
    $filestore = $tenantBase . '/output/reports/' . ($_REQUEST['clientnumber'] ?? '') . '/preview.pdf';
} else {
    if (($_REQUEST['mode'] ?? '') === "hse") {
        $filestore = $tenantBase . '/output/reports/' . ($_REQUEST['clientnumber'] ?? '') . '/' . ($_REQUEST['repnumber'] ?? '') . '_' . ($_REQUEST['items'] ?? '') . '_HSE.pdf';
    } else {
        $filestore = $tenantBase . '/output/reports/' . ($_REQUEST['clientnumber'] ?? '') . '/' . ($_REQUEST['repnumber'] ?? '') . '_' . ($_REQUEST['items'] ?? '') . '.pdf';
    }
}

// ---------- mPDF ----------
require_once '../../packages/mpd/vendor/autoload.php';
$orientation = $parts['orientation'] ?? 'P';

$mpdf = new \Mpdf\Mpdf([
    'mode' => 'utf-8',
    'format' => 'A4',
    'orientation' => $orientation,
    'margin_top' => 10,
    'margin_header' => 5,
    'margin_footer' => 3,
    'margin_left' => 10,
    'margin_right' => 10,
    'margin_bottom' => 6,          // was 20
    'setAutoTopMargin' => 'stretch',
    'setAutoBottomMargin' => 'stretch',
]);

$mpdf->shrink_tables_to_fit = 1;

// Load CSS so it applies to header/footer AND body
if (!empty($styleHtml)) {
    $mpdf->WriteHTML($styleHtml, \Mpdf\HTMLParserMode::HEADER_CSS);
}
$mpdf->WriteHTML('
<style>
    table {
        page-break-inside: auto;
    }

    thead {
        display: table-header-group;
    }

    tfoot {
        display: table-footer-group;
    }

    tr {
        page-break-inside: avoid;
        page-break-after: auto;
    }
</style>
', \Mpdf\HTMLParserMode::HEADER_CSS);
// Encode & set header/footer for odd+even
$header = mb_convert_encoding($header, 'UTF-8', 'UTF-8');
$footer = mb_convert_encoding($footer, 'UTF-8', 'UTF-8');
$tailFooter = mb_convert_encoding($tailFooter, 'UTF-8', 'UTF-8');
$mpdf->SetHTMLHeader($header, 'O');
$mpdf->SetHTMLHeader($header, 'E');
$mpdf->SetHTMLFooter($footer, 'O');
$mpdf->SetHTMLFooter($footer, 'E');

// Write body
$body = mb_convert_encoding($body, 'UTF-8', 'UTF-8');
$mpdf->WriteHTML($body);

if ($footerMode === 'tail' && trim($tailFooter) !== '') {
    $mpdf->SetHTMLFooter($tailFooter, 'O');
    $mpdf->SetHTMLFooter($tailFooter, 'E');
}

// Output
$mpdf->Output($filestore);
