<?php
/* ============================================================================
   WBMCZ — Member credentials
     - Premium ID card  (every logged-in member)
     - Seller certificate (issued automatically the moment a customer becomes
       a seller, and re-issued if it was ever missing)

   Both render as HTML/CSS and are downloaded as a high-resolution PNG via
   html2canvas, or printed / saved as PDF through the browser.
   ============================================================================ */

if (!function_exists('cred_ensure_schema')) {

function cred_ensure_schema($db) {
    static $done = false;
    if ($done) return;
    $done = true;
    try {
        $db->getConnection()->query("CREATE TABLE IF NOT EXISTS member_certificates (
            id INT AUTO_INCREMENT PRIMARY KEY,
            user_id INT NOT NULL,
            cert_no VARCHAR(40) NOT NULL,
            cert_type VARCHAR(20) NOT NULL DEFAULT 'seller',   -- seller | member
            holder_name VARCHAR(150) NULL,
            business_name VARCHAR(200) NULL,
            issued_on DATE NOT NULL,
            valid_till DATE NULL,
            status TINYINT(1) NOT NULL DEFAULT 1,
            created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
            UNIQUE KEY uniq_cert (cert_no),
            KEY idx_cert_user (user_id, cert_type)
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci");
    } catch (\Throwable $e) { /* ignore */ }
}

/* Member id shown on the card, e.g. WBMCZ-000032 */
function cred_member_id($user_id) {
    return 'WBMCZ-' . str_pad((int)$user_id, 6, '0', STR_PAD_LEFT);
}

/* Human role label */
function cred_role_label($db, $user) {
    $t = $user['user_type'] ?? 'customer';
    if ($t === 'seller') return 'Authorised Seller';
    if ($t === 'admin') {
        if (!empty($user['role_id'])) {
            try {
                $r = $db->select("SELECT role_name FROM roles WHERE id = ?", [(int)$user['role_id']]);
                if (!empty($r)) return $r[0]['role_name'];
            } catch (\Throwable $e) {}
        }
        return 'Administrator';
    }
    return !empty($user['is_subscribed']) ? 'Premium Member' : 'Member';
}

/**
 * Fetch the seller certificate, creating it on first call.
 * Returns null for anyone who is not a seller.
 */
function cred_get_certificate($db, $user, $auto_issue = true) {
    cred_ensure_schema($db);
    $uid = (int)$user['id'];
    if (($user['user_type'] ?? '') !== 'seller') return null;

    try {
        $r = $db->select("SELECT * FROM member_certificates WHERE user_id = ? AND cert_type = 'seller' ORDER BY id DESC LIMIT 1", [$uid]);
        if (!empty($r)) return $r[0];
    } catch (\Throwable $e) { return null; }

    if (!$auto_issue) return null;

    // Business name from the sellers table, if there is one
    $biz = '';
    try {
        $s = $db->select("SELECT business_name FROM sellers WHERE user_id = ? ORDER BY id DESC LIMIT 1", [$uid]);
        if (!empty($s)) $biz = (string)$s[0]['business_name'];
    } catch (\Throwable $e) {}

    $cert_no = 'WBMCZ/SLR/' . date('Y') . '/' . str_pad($uid, 5, '0', STR_PAD_LEFT);
    $issued  = date('Y-m-d');
    $valid   = date('Y-m-d', strtotime('+1 year'));

    try {
        $db->insert("INSERT INTO member_certificates (user_id, cert_no, cert_type, holder_name, business_name, issued_on, valid_till, status)
                     VALUES (?, ?, 'seller', ?, ?, ?, ?, 1)",
            [$uid, $cert_no, $user['name'] ?? '', $biz, $issued, $valid]);
    } catch (\Throwable $e) { /* duplicate — fall through and re-read */ }

    try {
        $r = $db->select("SELECT * FROM member_certificates WHERE user_id = ? AND cert_type = 'seller' ORDER BY id DESC LIMIT 1", [$uid]);
        return !empty($r) ? $r[0] : null;
    } catch (\Throwable $e) { return null; }
}

/* Called by admin when a customer is upgraded to a seller */
function cred_issue_seller_certificate($db, $user_id) {
    cred_ensure_schema($db);
    try {
        $u = $db->select("SELECT id, name, user_type FROM users WHERE id = ?", [(int)$user_id]);
        if (empty($u)) return null;
        $u = $u[0];
        $u['user_type'] = 'seller';   // the caller has just set this
        return cred_get_certificate($db, $u, true);
    } catch (\Throwable $e) { return null; }
}

/* ---------------------------------------------------------------------------
   Shared CSS + the html2canvas download helper.
   $rel = '' from the site root, '../' from /seller or /admin.
   --------------------------------------------------------------------------- */
function cred_assets($rel = '') {
    /* Guilloche security engraving — an inline SVG data-URI so that html2canvas
       rasterises it exactly the way the browser paints it.                     */
    $__rings = '';
    for ($i = 0; $i < 15; $i++) {
        $r  = 26 + $i * 15;
        $ry = round($r * 0.60, 1);
        $__rings .= "<ellipse cx='170' cy='262' rx='{$r}' ry='{$ry}' transform='rotate(" . ($i * 6) . " 170 262)'/>";
    }
    $__lines = '';
    for ($i = -6; $i < 26; $i++) {
        $x = $i * 22;
        $__lines .= "<path d='M{$x} 0 L" . ($x + 150) . " 540'/>";
    }
    $__guilloche = 'data:image/svg+xml;charset=utf8,' . rawurlencode(
        "<svg xmlns='http://www.w3.org/2000/svg' width='340' height='540' viewBox='0 0 340 540'>"
        . "<g fill='none' stroke='#ffffff' stroke-width='.7' stroke-opacity='.055'>{$__rings}</g>"
        . "<g fill='none' stroke='#ffffff' stroke-width='.5' stroke-opacity='.03'>{$__lines}</g>"
        . "</svg>"
    );

    ob_start(); ?>
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
<style>
    .cred-wrap { display:flex; flex-direction:column; align-items:center; gap:1.25rem; }

    /* =====================================================================
       PREMIUM ID CARD — front + back, CR80 portrait proportions (54 x 85.6mm)
       Colours arrive per card as inline custom properties:
         --g1 --g2 --g3  body gradient      --acc --acc2  metallic accent
         --glow  corner light               --ink  text that sits on the accent
       ===================================================================== */
    .idc-stage, .idc-stage *, .idc, .idc * { box-sizing:border-box; }
    .idc-stage { display:flex; flex-wrap:wrap; justify-content:center; align-items:flex-start; gap:26px; }
    .idc-side  { display:flex; flex-direction:column; align-items:center; gap:9px; }
    .idc-sidetag { font-size:9px; font-weight:800; letter-spacing:.22em; text-transform:uppercase; color:#94a3b8; }

    .idc {
        position:relative; width:340px; height:540px; border-radius:26px; overflow:hidden;
        background:linear-gradient(158deg,var(--g1) 0%,var(--g2) 46%,var(--g3) 100%);
        box-shadow:0 28px 64px -18px rgba(2,6,23,.7); color:#fff;
        font-family:'Inter',system-ui,-apple-system,sans-serif;
        border:1px solid rgba(255,255,255,.10);
    }
    .idc-guilloche {
        position:absolute; inset:0; z-index:1;
        background-image:url("<?php echo $__guilloche; ?>");
        background-size:340px 540px; background-repeat:no-repeat;
    }
    .idc-glow {
        position:absolute; z-index:1; top:-150px; right:-120px; width:330px; height:330px; border-radius:50%;
        background:radial-gradient(circle,var(--glow) 0%,rgba(255,255,255,0) 68%);
    }
    .idc-glow2 {
        position:absolute; z-index:1; left:-130px; bottom:-140px; width:320px; height:320px; border-radius:50%;
        background:radial-gradient(circle,rgba(255,255,255,.10) 0%,rgba(255,255,255,0) 68%);
    }
    .idc-sheen {
        position:absolute; inset:0; z-index:1;
        background:linear-gradient(112deg,rgba(255,255,255,0) 26%,rgba(255,255,255,.09) 42%,rgba(255,255,255,0) 56%);
    }
    .idc-edge { position:absolute; inset:8px; z-index:2; border:1px solid rgba(255,255,255,.12); border-radius:19px; }
    .idc-topfoil {
        position:absolute; top:0; left:0; right:0; height:4px; z-index:3;
        background:linear-gradient(90deg,rgba(255,255,255,0),var(--acc) 22%,var(--acc2) 50%,var(--acc) 78%,rgba(255,255,255,0));
    }
    .idc-botfoil {
        position:absolute; bottom:0; left:0; right:0; height:4px; z-index:3;
        background:linear-gradient(90deg,rgba(255,255,255,0),var(--acc) 30%,var(--acc2) 50%,var(--acc) 70%,rgba(255,255,255,0));
    }

    .idc-inner { position:relative; z-index:4; padding:18px 18px 14px; height:100%; display:flex; flex-direction:column; overflow:hidden; }

    /* ---------- header ---------- */
    .idc-top { display:flex; align-items:center; gap:10px; }
    .idc-logo {
        width:40px; height:40px; border-radius:12px; background:#fff; padding:4px; object-fit:contain;
        flex-shrink:0; border:1px solid rgba(255,255,255,.5);
    }
    .idc-brand { font-size:15px; font-weight:900; letter-spacing:.10em; color:#fff; line-height:1.1; text-transform:uppercase; }
    .idc-sub   { font-size:7.5px; letter-spacing:.24em; color:var(--acc); text-transform:uppercase; margin-top:3px; font-weight:800; }
    .idc-hair  { height:1px; margin-top:10px; opacity:.55;
                 background:linear-gradient(90deg,rgba(255,255,255,0),var(--acc) 18%,var(--acc) 82%,rgba(255,255,255,0)); }

    /* ---------- portrait ---------- */
    .idc-photo-wrap { display:flex; justify-content:center; margin-top:12px; }
    .idc-photo-frame {
        padding:3px; border-radius:16px;
        background:linear-gradient(150deg,var(--acc2),var(--acc) 42%,rgba(255,255,255,.35) 70%,var(--acc));
    }
    .idc-photo {
        display:block; width:134px; height:158px; border-radius:13px; object-fit:cover;
        background:rgba(0,0,0,.28); border:2px solid rgba(0,0,0,.22);
    }
    .idc-photo-fallback {
        width:134px; height:158px; border-radius:13px; display:flex; align-items:center; justify-content:center;
        font-size:44px; font-weight:900; color:var(--acc); background:rgba(0,0,0,.30);
        border:2px solid rgba(0,0,0,.22); letter-spacing:.04em;
    }

    /* ---------- name plate ---------- */
    .idc-plate {
        margin:11px -2px 0; padding:7px 10px 8px; text-align:center; border-radius:12px;
        background:linear-gradient(180deg,rgba(0,0,0,.36),rgba(0,0,0,.18));
        border-top:1px solid var(--acc); border-bottom:1px solid var(--acc);
    }
    .idc-name { font-size:16px; font-weight:900; letter-spacing:.06em; line-height:1.15; text-transform:uppercase; color:#fff; }
    .idc-role {
        display:inline-block; margin-top:6px; padding:3px 12px; border-radius:999px;
        background:linear-gradient(90deg,var(--acc),var(--acc2)); color:var(--ink);
        font-size:8.5px; font-weight:900; letter-spacing:.15em; text-transform:uppercase;
    }

    /* ---------- data grid ---------- */
    .idc-grid { margin-top:10px; display:grid; grid-template-columns:1fr 1fr; gap:6px; }
    .idc-cell {
        background:rgba(255,255,255,.07); border:1px solid rgba(255,255,255,.11);
        border-radius:10px; padding:6px 9px; min-width:0;
    }
    .idc-cell.wide { grid-column:1 / -1; }
    .idc-k { display:block; font-size:7px; letter-spacing:.16em; text-transform:uppercase;
             color:rgba(255,255,255,.5); font-weight:800; }
    .idc-v { display:block; font-size:11.5px; font-weight:800; color:#fff; margin-top:3px;
             letter-spacing:.04em; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
    .idc-v.acc  { color:var(--acc); }
    .idc-v.mono { font-family:'Courier New',ui-monospace,monospace; letter-spacing:.10em; font-size:12px; }

    /* ---------- footer ---------- */
    .idc-foot { margin-top:auto; padding-top:9px; display:flex; align-items:center; gap:9px;
                border-top:1px solid rgba(255,255,255,.13); }
    .idc-holo {
        width:34px; height:34px; border-radius:50%; flex-shrink:0;
        background:radial-gradient(circle at 34% 30%,#ffffff 0%,var(--acc2) 26%,var(--acc) 52%,rgba(255,255,255,.65) 74%,var(--acc) 100%);
        border:1px solid rgba(255,255,255,.55);
        display:flex; align-items:center; justify-content:center;
        font-size:7.5px; font-weight:900; color:var(--ink); letter-spacing:.02em;
    }
    .idc-org  { font-size:9.5px; font-weight:900; letter-spacing:.09em; color:#fff; text-transform:uppercase; line-height:1.3; }
    .idc-addr { font-size:7.5px; font-weight:600; letter-spacing:.05em; color:rgba(255,255,255,.62); line-height:1.5; margin-top:2px; }
    .idc-micro { margin-top:5px; font-size:4.6px; letter-spacing:.10em; color:rgba(255,255,255,.30);
                 white-space:nowrap; overflow:hidden; text-transform:uppercase; }

    /* ---------- back face ---------- */
    .idcb-strip { margin:11px -18px 0; height:34px; background:linear-gradient(180deg,#0a0a0a,#1e1e1e 55%,#0a0a0a); }
    .idcb-sig {
        margin-top:11px; height:32px; border-radius:6px; background:#f4f4ef;
        display:flex; align-items:flex-end; justify-content:space-between; padding:4px 8px;
        border:1px solid rgba(0,0,0,.18);
    }
    .idcb-sigline { font-family:'Georgia','Times New Roman',serif; font-size:14px; color:#1f2937; opacity:.75; }
    .idcb-sigk    { font-size:6.5px; letter-spacing:.14em; text-transform:uppercase; color:#6b7280; font-weight:800; }

    .idcb-qrrow { margin-top:11px; display:flex; align-items:center; gap:11px; }
    .idc-qr { width:70px; height:70px; border-radius:9px; background:#fff; padding:4px; flex-shrink:0; }
    .idcb-qrtxt { font-size:8px; line-height:1.7; color:rgba(255,255,255,.66); letter-spacing:.06em; }
    .idcb-qrtxt b { color:var(--acc); display:block; font-size:9px; letter-spacing:.12em; text-transform:uppercase; }

    .idc-rows { margin-top:10px; display:flex; flex-direction:column; gap:5px; }
    .idc-row  { display:flex; align-items:center; justify-content:space-between; gap:8px;
                background:rgba(255,255,255,.06); border:1px solid rgba(255,255,255,.10);
                border-radius:9px; padding:5px 10px; }
    .idc-row .idc-k { font-size:7px; }
    .idc-row .idc-v { margin-top:0; font-size:10.5px; text-align:right; }

    .idcb-terms   { margin-top:9px; font-size:6.4px; line-height:1.6; color:rgba(255,255,255,.45); letter-spacing:.03em; }
    .idcb-barcode { margin-top:9px; display:flex; align-items:flex-end; gap:0; height:28px;
                    background:#fff; padding:4px 7px; border-radius:5px; }
    .idcb-barcode i { display:block; background:#0b0b0b; height:100%; }
    .idcb-bcno { text-align:center; font-family:'Courier New',monospace; font-size:7.5px;
                 letter-spacing:.28em; color:rgba(255,255,255,.55); margin-top:4px; }

    /* ---------- CERTIFICATE ---------- */
    .cert {
        position:relative; width:880px; max-width:100%; aspect-ratio:1.414/1;
        background:linear-gradient(140deg,#fffdf7 0%,#fdf8ec 50%,#fffdf7 100%);
        border-radius:10px; overflow:hidden; color:#1a2238;
        box-shadow:0 30px 70px -20px rgba(15,23,42,.45);
        font-family:'Inter',system-ui,sans-serif;
    }
    .cert-border { position:absolute; inset:14px; border:2px solid #d4af37; border-radius:5px; }
    .cert-border2 { position:absolute; inset:21px; border:1px solid rgba(212,175,55,.42); border-radius:3px; }
    .cert-corner { position:absolute; width:52px; height:52px; border:3px solid #d4af37; }
    .cert-corner.tl { top:26px; left:26px; border-right:0; border-bottom:0; border-radius:6px 0 0 0; }
    .cert-corner.tr { top:26px; right:26px; border-left:0; border-bottom:0; border-radius:0 6px 0 0; }
    .cert-corner.bl { bottom:26px; left:26px; border-right:0; border-top:0; border-radius:0 0 0 6px; }
    .cert-corner.br { bottom:26px; right:26px; border-left:0; border-top:0; border-radius:0 0 6px 0; }
    .cert-seal-bg {
        position:absolute; top:50%; left:50%; transform:translate(-50%,-50%);
        width:400px; height:400px; border-radius:50%;
        background:radial-gradient(circle,rgba(212,175,55,.09) 0%,transparent 66%);
    }
    .cert-inner { position:relative; z-index:2; height:100%; padding:52px 62px 40px; display:flex; flex-direction:column; text-align:center; }

    .cert-head { display:flex; align-items:center; justify-content:center; gap:12px; }
    .cert-logo { width:46px; height:46px; object-fit:contain; }
    .cert-brand { font-size:20px; font-weight:900; letter-spacing:.16em; color:#12203a; }
    .cert-tag { font-size:8px; letter-spacing:.3em; text-transform:uppercase; color:#9a8347; margin-top:3px; }

    .cert-rule { width:76px; height:3px; background:linear-gradient(90deg,transparent,#d4af37,transparent); margin:18px auto 0; }
    .cert-title { font-size:34px; font-weight:900; letter-spacing:.13em; text-transform:uppercase; color:#12203a; margin-top:14px; line-height:1.05; }
    .cert-title small { display:block; font-size:11px; letter-spacing:.34em; color:#9a8347; font-weight:700; margin-top:7px; }

    .cert-intro { font-size:11.5px; letter-spacing:.14em; text-transform:uppercase; color:#6b7280; margin-top:24px; }
    .cert-name {
        font-family:'Georgia','Times New Roman',serif; font-size:40px; font-weight:700; color:#12203a;
        margin-top:8px; line-height:1.15; padding-bottom:10px;
        border-bottom:2px solid rgba(212,175,55,.55); display:inline-block; min-width:340px;
    }
    .cert-biz { font-size:13px; font-weight:800; letter-spacing:.05em; color:#9a8347; margin-top:10px; text-transform:uppercase; }
    .cert-body { font-size:12.5px; line-height:1.85; color:#4b5563; margin-top:16px; max-width:620px; margin-left:auto; margin-right:auto; }

    .cert-foot { margin-top:auto; display:flex; align-items:flex-end; justify-content:space-between; gap:20px; padding-top:22px; }
    .cert-col { text-align:center; flex:1; }
    .cert-line { border-top:1.5px solid #12203a; width:150px; margin:0 auto 5px; }
    .cert-k { font-size:8px; letter-spacing:.16em; text-transform:uppercase; color:#9ca3af; font-weight:700; }
    .cert-val { font-size:11.5px; font-weight:800; color:#12203a; }

    .cert-seal { width:104px; height:104px; border-radius:50%; flex-shrink:0;
        background:radial-gradient(circle at 32% 28%,#f5dd8f,#d4af37 58%,#a8842c);
        display:flex; flex-direction:column; align-items:center; justify-content:center;
        color:#12203a; box-shadow:0 8px 22px rgba(168,132,44,.42); border:3px solid rgba(255,255,255,.55); }
    .cert-seal b { font-size:9.5px; letter-spacing:.11em; line-height:1.25; text-align:center; }
    .cert-seal span { font-size:7px; letter-spacing:.18em; margin-top:3px; opacity:.75; }

    .cred-btn { display:inline-flex; align-items:center; justify-content:center; gap:.5rem;
        padding:.7rem 1.35rem; border-radius:.85rem; font-weight:700; font-size:.82rem;
        border:0; cursor:pointer; transition:transform .15s, box-shadow .15s; }
    .cred-btn:hover { transform:translateY(-1px); }
    .cred-btn-gold { background:linear-gradient(90deg,#d4af37,#b8942e); color:#12203a; box-shadow:0 8px 20px -6px rgba(212,175,55,.6); }
    .cred-btn-dark { background:#1e293b; color:#fff; }
    .cred-btn-ghost { background:#f1f5f9; color:#475569; }

    .cert-scroll { width:100%; overflow-x:auto; padding-bottom:6px; }

    /* ---------- PRINT: only the cloned card/certificate is on the page ---------- */
    #credPrintHost { display:none; }
    @media print {
        @page { margin: 8mm; }
        html.cred-printing, html.cred-printing body { background:#fff !important; height:auto !important; overflow:visible !important; }
        html.cred-printing body > * { display:none !important; }
        html.cred-printing body > #credPrintHost {
            display:flex !important; align-items:flex-start; justify-content:center;
            position:static !important; width:100% !important;
        }
        html.cred-printing #credPrintHost .cred-noprint { display:none !important; }
        html.cred-printing #credPrintHost .idc  { box-shadow:none !important; }
        html.cred-printing #credPrintHost .idc-stage { gap:8mm !important; }
        html.cred-printing #credPrintHost .idc-sidetag { color:#64748b !important; }
        html.cred-printing #credPrintHost .cert { box-shadow:none !important; width:100% !important; }
        html.cred-printing #credPrintHost .cert-scroll { overflow:visible !important; }
    }
</style>
<script>
/* ---- shared: render an element to a canvas ---- */
function credCanvas(el) {
    return html2canvas(el, {
        scale: 3, backgroundColor: null, useCORS: true, allowTaint: false,
        logging: false, windowWidth: el.scrollWidth, windowHeight: el.scrollHeight
    });
}

/* Download any element as a high-resolution PNG */
function credDownload(elId, filename) {
    var el = document.getElementById(elId);
    if (!el || typeof html2canvas === 'undefined') { credPrint(elId); return; }
    credCanvas(el).then(function (canvas) {
        var a = document.createElement('a');
        a.download = filename + '.png';
        a.href = canvas.toDataURL('image/png');
        a.click();
    }).catch(function () { credPrint(elId); });
}

/* Download as a REAL PDF, page sized exactly to the artwork (mm).
   ID card  -> 54 x 85.6 mm  (standard portrait ID card)
   Cert     -> 297 x 210 mm  (A4 landscape)                                */
function credPdf(elId, filename, wmm, hmm) {
    var el = document.getElementById(elId);
    if (!el || typeof html2canvas === 'undefined' || !window.jspdf) { credPrint(elId); return; }
    var btn = document.activeElement;
    if (btn && btn.tagName === 'BUTTON') { btn.disabled = true; btn.style.opacity = .6; }

    credCanvas(el).then(function (canvas) {
        var JsPDF = window.jspdf.jsPDF;
        var pdf = new JsPDF({
            orientation: (wmm > hmm ? 'landscape' : 'portrait'),
            unit: 'mm',
            format: [wmm, hmm],
            compress: true
        });
        /* Fit the artwork inside the page while keeping its aspect ratio */
        var ratio = canvas.width / canvas.height;
        var w = wmm, h = wmm / ratio;
        if (h > hmm) { h = hmm; w = hmm * ratio; }
        pdf.addImage(canvas.toDataURL('image/jpeg', 0.96), 'JPEG', (wmm - w) / 2, (hmm - h) / 2, w, h, undefined, 'FAST');
        pdf.save(filename + '.pdf');
    }).catch(function () { credPrint(elId); })
      .finally(function () { if (btn && btn.tagName === 'BUTTON') { btn.disabled = false; btn.style.opacity = 1; } });
}

/* Place a canvas on the current PDF page, fitted and centred */
function credFit(pdf, canvas, wmm, hmm) {
    var ratio = canvas.width / canvas.height;
    var w = wmm, h = wmm / ratio;
    if (h > hmm) { h = hmm; w = hmm * ratio; }
    pdf.addImage(canvas.toDataURL('image/jpeg', 0.96), 'JPEG', (wmm - w) / 2, (hmm - h) / 2, w, h, undefined, 'FAST');
}

/* ID card -> a real 2-page PDF at 54 x 85.6 mm: page 1 front, page 2 back */
function credPdfCard(frontId, backId, filename) {
    var f = document.getElementById(frontId), b = document.getElementById(backId);
    if (!f || typeof html2canvas === 'undefined' || !window.jspdf) { credPrintCard(frontId, backId); return; }
    var btn = document.activeElement;
    if (btn && btn.tagName === 'BUTTON') { btn.disabled = true; btn.style.opacity = .6; }

    var W = 54, H = 85.6;
    var jobs = [credCanvas(f)];
    if (b) jobs.push(credCanvas(b));

    Promise.all(jobs).then(function (cvs) {
        var JsPDF = window.jspdf.jsPDF;
        var pdf = new JsPDF({ orientation: 'portrait', unit: 'mm', format: [W, H], compress: true });
        credFit(pdf, cvs[0], W, H);
        if (cvs[1]) { pdf.addPage([W, H], 'portrait'); credFit(pdf, cvs[1], W, H); }
        pdf.save(filename + '.pdf');
    }).catch(function () { credPrintCard(frontId, backId); })
      .finally(function () { if (btn && btn.tagName === 'BUTTON') { btn.disabled = false; btn.style.opacity = 1; } });
}

/* Download front + back as two separate high-resolution PNG files */
function credDownloadCard(frontId, backId, filename) {
    credDownload(frontId, filename + '-front');
    setTimeout(function () { credDownload(backId, filename + '-back'); }, 700);
}

/* Print — clones the artwork to the top of <body> so the browser preview
   shows the card alone (and never a mostly-blank page).                    */
function credPrint(elId) {
    var el = document.getElementById(elId);
    if (!el) return;
    var old = document.getElementById('credPrintHost');
    if (old && old.parentNode) old.parentNode.removeChild(old);

    var host = document.createElement('div');
    host.id = 'credPrintHost';
    host.appendChild(el.cloneNode(true));
    document.body.appendChild(host);
    document.documentElement.classList.add('cred-printing');

    var cleanup = function () {
        document.documentElement.classList.remove('cred-printing');
        if (host.parentNode) host.parentNode.removeChild(host);
        window.removeEventListener('afterprint', cleanup);
    };
    window.addEventListener('afterprint', cleanup);
    setTimeout(function () { window.print(); }, 60);
    setTimeout(cleanup, 3000);
}

/* Print both faces of the ID card side by side on one sheet */
function credPrintCard(frontId, backId) {
    var f = document.getElementById(frontId), b = document.getElementById(backId);
    if (!f) return;
    var old = document.getElementById('credPrintHost');
    if (old && old.parentNode) old.parentNode.removeChild(old);

    var host = document.createElement('div');
    host.id = 'credPrintHost';
    var stage = document.createElement('div');
    stage.className = 'idc-stage';
    stage.appendChild(f.cloneNode(true));
    if (b) stage.appendChild(b.cloneNode(true));
    host.appendChild(stage);
    document.body.appendChild(host);
    document.documentElement.classList.add('cred-printing');

    var cleanup = function () {
        document.documentElement.classList.remove('cred-printing');
        if (host.parentNode) host.parentNode.removeChild(host);
        window.removeEventListener('afterprint', cleanup);
    };
    window.addEventListener('afterprint', cleanup);
    setTimeout(function () { window.print(); }, 60);
    setTimeout(cleanup, 3000);
}
</script>
<?php
    return ob_get_clean();
}

/* ---------------------------------------------------------------------------
   ID CARD — helpers
   --------------------------------------------------------------------------- */

/* Which of the card columns actually exist on this database? (cached) */
function cred_card_cols($db) {
    static $cols = null;
    if ($cols !== null) return $cols;
    $cols = [];
    try {
        $r = $db->getConnection()->query("SHOW COLUMNS FROM `users`");
        if ($r) { while ($row = $r->fetch_assoc()) { $cols[strtolower($row['Field'])] = true; } }
    } catch (\Throwable $e) { /* ignore */ }
    return $cols;
}

/**
 * Permanent card identity for a member.
 *
 * Card number  16 digits, printed 4-4-4-4  (e.g. 5021 3877 4162 1018)
 * Employee ID  WB / WS / WA + zero padded user id  (e.g. WB1018)
 *
 * The numbers are derived from the user id, so they are always the same for
 * the same member, and are written back to `users` the first time the card is
 * opened — provided testsmigration.php has been run. If the columns are not
 * there yet the card still renders, it simply does not persist anything.
 */
function cred_card_identity($db, $user) {
    $uid  = (int)$user['id'];
    $type = $user['user_type'] ?? 'customer';
    $pre  = ($type === 'admin') ? 'WA' : (($type === 'seller') ? 'WS' : 'WB');

    $card = trim((string)($user['card_number']    ?? ''));
    $emp  = trim((string)($user['employee_code']  ?? ''));
    $iss  = trim((string)($user['card_issued_on'] ?? ''));
    $till = trim((string)($user['card_valid_till']?? ''));

    if ($emp === '') $emp = $pre . str_pad((string)$uid, 4, '0', STR_PAD_LEFT);

    if ($card === '') {
        $h    = sprintf('%010u', crc32('WBMCZ|CARD|' . $uid));      // stable per user
        $card = '5021' . substr($h, 0, 8) . str_pad((string)($uid % 10000), 4, '0', STR_PAD_LEFT);
    }
    $card = preg_replace('/\D/', '', $card);
    if (strlen($card) < 16) $card = str_pad($card, 16, '0', STR_PAD_LEFT);

    if ($iss === '' || $iss === '0000-00-00') {
        $iss = !empty($user['created_at']) ? date('Y-m-d', strtotime($user['created_at'])) : date('Y-m-d');
    }
    if ($till === '' || $till === '0000-00-00') {
        $till = date('Y-m-d', strtotime($iss . ' +5 years'));
    }

    /* write back once — only when every column is present */
    $cols = cred_card_cols($db);
    $have = isset($cols['card_number'], $cols['employee_code'], $cols['card_issued_on'], $cols['card_valid_till']);
    $gap  = empty($user['card_number']) || empty($user['employee_code'])
         || empty($user['card_issued_on']) || empty($user['card_valid_till']);
    if ($have && $gap) {
        try {
            $db->insert("UPDATE users SET card_number = ?, employee_code = ?, card_issued_on = ?, card_valid_till = ? WHERE id = ?",
                        [$card, $emp, $iss, $till, $uid]);
        } catch (\Throwable $e) { /* never break the page */ }
    }

    return [
        'card'      => $card,
        'card_fmt'  => trim(chunk_split($card, 4, ' ')),
        'emp'       => $emp,
        'issued'    => $iss,
        'valid'     => $till,
        'active'    => (!isset($cols['card_status']) || !isset($user['card_status'])) ? 1 : (int)$user['card_status'],
    ];
}

/* Role driven colour scheme — every role carries its own metal */
function cred_card_theme($db, $user) {
    $type = $user['user_type'] ?? 'customer';

    if ($type === 'admin') {                       // ONYX — staff / administration
        return ['key'=>'onyx','g1'=>'#05070d','g2'=>'#151f36','g3'=>'#05070d',
                'acc'=>'#d4af37','acc2'=>'#f7e6a5','glow'=>'rgba(212,175,55,.30)','ink'=>'#0a0f1c',
                'tag'=>'Staff Identity Card','holo'=>'STAFF'];
    }
    if ($type === 'seller') {                      // EMERALD — authorised seller
        return ['key'=>'emerald','g1'=>'#03211b','g2'=>'#0b6350','g3'=>'#03211b',
                'acc'=>'#f0cd82','acc2'=>'#fff0c8','glow'=>'rgba(240,205,130,.28)','ink'=>'#04231d',
                'tag'=>'Authorised Partner Card','holo'=>'PARTNER'];
    }
    if (!empty($user['is_subscribed'])) {          // GOLD — premium member
        return ['key'=>'gold','g1'=>'#16100a','g2'=>'#4c3a16','g3'=>'#100b06',
                'acc'=>'#f2ce6b','acc2'=>'#fff3c4','glow'=>'rgba(242,206,107,.32)','ink'=>'#231802',
                'tag'=>'Premium Membership Card','holo'=>'PREMIUM'];
    }
    return ['key'=>'teal','g1'=>'#043c3c','g2'=>'#0f8d7e','g3'=>'#032e2f',   // TEAL — member
            'acc'=>'#9df3dd','acc2'=>'#e6fffa','glow'=>'rgba(157,243,221,.26)','ink'=>'#04322f',
            'tag'=>'Official Identity Card','holo'=>'MEMBER'];
}

/* Deterministic bar pattern drawn from the card number */
function cred_barcode_bars($seed) {
    $bars = '';
    $s    = preg_replace('/\D/', '', $seed) ?: '0';
    $n    = strlen($s);
    for ($i = 0; $i < 45; $i++) {
        $d    = (int)$s[$i % $n];
        $bar  = 2 + ($d % 3);                     // 2–4 px of ink
        $gap  = 2 + (($d * 7 + $i) % 3);          // 2–4 px of paper
        $bars .= '<i style="width:' . $bar . 'px"></i>';
        $bars .= '<i style="width:' . $gap . 'px;background:transparent"></i>';
    }
    return $bars;
}

/* ---------------------------------------------------------------------------
   ID CARD — front + back
   --------------------------------------------------------------------------- */
function cred_render_id_card($db, $user, $opts = []) {
    $rel   = $opts['rel'] ?? '';
    $brand = $opts['brand'] ?? 'WBMCZ';
    $logo  = $opts['logo'] ?? ($rel . 'assets/images/logo.png');

    $uid      = (int)$user['id'];
    $memberId = cred_member_id($uid);
    $role     = cred_role_label($db, $user);
    $th       = cred_card_theme($db, $user);
    $id       = cred_card_identity($db, $user);

    $joined   = !empty($user['created_at']) ? date('d M Y', strtotime($user['created_at'])) : '—';
    $issued   = date('d M Y', strtotime($id['issued']));
    $validSht = date('m / y',  strtotime($id['valid']));
    $validLng = date('d M Y',  strtotime($id['valid']));
    $photo    = !empty($user['profile_pic']) ? $rel . 'uploads/profiles/' . $user['profile_pic'] : '';
    $initials = strtoupper(mb_substr(trim($user['name'] ?? 'M'), 0, 2));

    /* Company details for the footer / return address */
    $addr  = function_exists('getSetting') ? (string)getSetting('company_address', '') : '';
    $phone = function_exists('getSetting') ? (string)getSetting('company_phone', '')   : '';
    $mail  = function_exists('getSetting') ? (string)getSetting('company_email', '')   : '';
    if ($addr === '') $addr = 'South 24 Parganas, West Bengal, India';

    /* QR points at the verification URL */
    $verify = (defined('SITE_URL') ? SITE_URL : '') . '/login.php?member=' . urlencode($memberId);
    $qr     = 'https://api.qrserver.com/v1/create-qr-code/?size=200x200&margin=0&data=' . urlencode($verify);

    /* Subscription — only shown when the member actually has one */
    $is_sub   = !empty($user['is_subscribed']);
    $sub_till = '';
    if ($is_sub) {
        foreach (['subscription_expiry', 'subscription_end', 'subscribed_till', 'subscription_date'] as $__c) {
            if (!empty($user[$__c])) { $sub_till = date('d M Y', strtotime($user[$__c])); break; }
        }
    }

    $type = $user['user_type'] ?? 'customer';
    $biz  = '';
    if ($type === 'seller') {
        try {
            $s = $db->select("SELECT business_name FROM sellers WHERE user_id = ? ORDER BY id DESC LIMIT 1", [$uid]);
            if (!empty($s)) $biz = (string)$s[0]['business_name'];
        } catch (\Throwable $e) {}
    }

    $vars = 'style="--g1:' . $th['g1'] . ';--g2:' . $th['g2'] . ';--g3:' . $th['g3']
          . ';--acc:' . $th['acc'] . ';--acc2:' . $th['acc2'] . ';--glow:' . $th['glow']
          . ';--ink:' . $th['ink'] . '"';

    $micro = str_repeat(strtoupper($brand) . ' · SECURE · ' . $id['emp'] . ' · ', 6);
    $fname = $id['emp'] . '-' . $memberId;

    ob_start(); ?>
<div class="cred-wrap">
    <div class="idc-stage">

        <!-- ============================ FRONT ============================ -->
        <div class="idc-side">
            <div class="idc" id="credIdCard" <?php echo $vars; ?>>
                <div class="idc-guilloche"></div>
                <div class="idc-glow"></div>
                <div class="idc-glow2"></div>
                <div class="idc-sheen"></div>
                <div class="idc-edge"></div>
                <div class="idc-topfoil"></div>
                <div class="idc-botfoil"></div>

                <div class="idc-inner">
                    <div class="idc-top">
                        <img src="<?php echo htmlspecialchars($logo); ?>" class="idc-logo" alt="" crossorigin="anonymous">
                        <div>
                            <div class="idc-brand"><?php echo htmlspecialchars(strtoupper($brand)); ?></div>
                            <div class="idc-sub"><?php echo htmlspecialchars($th['tag']); ?></div>
                        </div>
                    </div>
                    <div class="idc-hair"></div>

                    <div class="idc-photo-wrap">
                        <div class="idc-photo-frame">
                            <?php if ($photo): ?>
                                <img src="<?php echo htmlspecialchars($photo); ?>" class="idc-photo" alt="" crossorigin="anonymous">
                            <?php else: ?>
                                <div class="idc-photo-fallback"><?php echo htmlspecialchars($initials); ?></div>
                            <?php endif; ?>
                        </div>
                    </div>

                    <div class="idc-plate">
                        <div class="idc-name"><?php echo htmlspecialchars($user['name'] ?? 'Member'); ?></div>
                        <span class="idc-role"><?php echo htmlspecialchars($role); ?></span>
                    </div>

                    <div class="idc-grid">
                        <div class="idc-cell wide">
                            <span class="idc-k">Card Number</span>
                            <span class="idc-v mono acc"><?php echo htmlspecialchars($id['card_fmt']); ?></span>
                        </div>
                        <div class="idc-cell">
                            <span class="idc-k">Employee ID</span>
                            <span class="idc-v"><?php echo htmlspecialchars($id['emp']); ?></span>
                        </div>
                        <div class="idc-cell">
                            <span class="idc-k">Valid Thru</span>
                            <span class="idc-v"><?php echo htmlspecialchars($validSht); ?></span>
                        </div>
                        <div class="idc-cell">
                            <span class="idc-k">Member ID</span>
                            <span class="idc-v"><?php echo htmlspecialchars($memberId); ?></span>
                        </div>
                        <div class="idc-cell">
                            <span class="idc-k">Member Since</span>
                            <span class="idc-v"><?php echo htmlspecialchars($joined); ?></span>
                        </div>
                    </div>

                    <div class="idc-foot">
                        <div class="idc-holo"><?php echo htmlspecialchars(mb_substr($th['holo'], 0, 7)); ?></div>
                        <div style="min-width:0">
                            <div class="idc-org"><?php echo htmlspecialchars(strtoupper($brand)); ?></div>
                            <div class="idc-addr"><?php echo htmlspecialchars($addr); ?></div>
                        </div>
                    </div>
                    <div class="idc-micro"><?php echo htmlspecialchars($micro); ?></div>
                </div>
            </div>
            <div class="idc-sidetag cred-noprint">Front</div>
        </div>

        <!-- ============================ BACK ============================= -->
        <div class="idc-side">
            <div class="idc" id="credIdCardBack" <?php echo $vars; ?>>
                <div class="idc-guilloche"></div>
                <div class="idc-glow"></div>
                <div class="idc-glow2"></div>
                <div class="idc-sheen"></div>
                <div class="idc-edge"></div>
                <div class="idc-topfoil"></div>
                <div class="idc-botfoil"></div>

                <div class="idc-inner">
                    <div class="idc-top">
                        <img src="<?php echo htmlspecialchars($logo); ?>" class="idc-logo" alt="" crossorigin="anonymous">
                        <div>
                            <div class="idc-brand"><?php echo htmlspecialchars(strtoupper($brand)); ?></div>
                            <div class="idc-sub">Verification &amp; Terms</div>
                        </div>
                    </div>

                    <div class="idcb-strip"></div>

                    <div class="idcb-sig">
                        <span class="idcb-sigline"><?php echo htmlspecialchars($user['name'] ?? ''); ?></span>
                        <span class="idcb-sigk">Holder&rsquo;s signature</span>
                    </div>

                    <div class="idcb-qrrow">
                        <img src="<?php echo htmlspecialchars($qr); ?>" class="idc-qr" alt="QR" crossorigin="anonymous">
                        <div class="idcb-qrtxt">
                            <b>Scan to verify</b>
                            Member ID <?php echo htmlspecialchars($memberId); ?><br>
                            Issued <?php echo htmlspecialchars($issued); ?><br>
                            Valid till <?php echo htmlspecialchars($validLng); ?>
                        </div>
                    </div>

                    <div class="idc-rows">
                        <div class="idc-row">
                            <span class="idc-k">User ID</span>
                            <span class="idc-v"><?php echo $uid; ?></span>
                        </div>
                        <div class="idc-row">
                            <span class="idc-k">Mobile</span>
                            <span class="idc-v"><?php echo htmlspecialchars($user['mobile'] ?? '—'); ?></span>
                        </div>
                        <?php if ($biz !== ''): ?>
                        <div class="idc-row">
                            <span class="idc-k">Business</span>
                            <span class="idc-v"><?php echo htmlspecialchars($biz); ?></span>
                        </div>
                        <?php endif; ?>
                        <?php if ($is_sub): ?>
                        <div class="idc-row">
                            <span class="idc-k">Subscription</span>
                            <span class="idc-v acc">ACTIVE<?php echo $sub_till ? ' · ' . htmlspecialchars($sub_till) : ''; ?></span>
                        </div>
                        <?php endif; ?>
                        <?php if ($phone !== ''): ?>
                        <div class="idc-row">
                            <span class="idc-k">Helpdesk</span>
                            <span class="idc-v"><?php echo htmlspecialchars($phone); ?></span>
                        </div>
                        <?php endif; ?>
                        <div class="idc-row">
                            <span class="idc-k">Member Since</span>
                            <span class="idc-v"><?php echo htmlspecialchars($joined); ?></span>
                        </div>
                    </div>

                    <div class="idcb-terms">
                        This card is the property of <?php echo htmlspecialchars(strtoupper($brand)); ?> and is
                        non-transferable. It must be produced on demand and surrendered when membership ends.
                        Misuse will lead to cancellation without notice.
                        <?php if ($phone !== '' || $mail !== ''): ?>
                        If found, please return to <?php echo htmlspecialchars($addr); ?><?php
                            echo $phone !== '' ? ' · ' . htmlspecialchars($phone) : '';
                            echo $mail  !== '' ? ' · ' . htmlspecialchars($mail)  : ''; ?>.
                        <?php endif; ?>
                    </div>

                    <div class="idcb-barcode"><?php echo cred_barcode_bars($id['card']); ?></div>
                    <div class="idcb-bcno"><?php echo htmlspecialchars($id['card']); ?></div>

                    <div class="idc-foot">
                        <div class="idc-holo">&#10004;</div>
                        <div style="min-width:0">
                            <div class="idc-org">Authorised Signatory</div>
                            <div class="idc-addr"><?php echo htmlspecialchars(strtoupper($brand)); ?> · Issuing Authority</div>
                        </div>
                    </div>
                    <div class="idc-micro"><?php echo htmlspecialchars($micro); ?></div>
                </div>
            </div>
            <div class="idc-sidetag cred-noprint">Back</div>
        </div>

    </div>

    <div class="flex flex-wrap gap-2 justify-center cred-noprint">
        <button type="button" class="cred-btn cred-btn-gold" onclick="credPdfCard('credIdCard','credIdCardBack','<?php echo htmlspecialchars($fname); ?>')">
            <i class="fas fa-file-pdf"></i> Download PDF (2 pages)
        </button>
        <button type="button" class="cred-btn cred-btn-dark" onclick="credDownloadCard('credIdCard','credIdCardBack','<?php echo htmlspecialchars($fname); ?>')">
            <i class="fas fa-image"></i> Download PNG
        </button>
        <button type="button" class="cred-btn cred-btn-ghost" onclick="credPrintCard('credIdCard','credIdCardBack')">
            <i class="fas fa-print"></i> Print
        </button>
    </div>
</div>
<?php
    return ob_get_clean();
}

/* ---------------------------------------------------------------------------
   SELLER CERTIFICATE
   --------------------------------------------------------------------------- */
function cred_render_certificate($db, $user, $cert, $opts = []) {
    $rel   = $opts['rel'] ?? '';
    $brand = $opts['brand'] ?? 'WBMCZ';
    $logo  = $opts['logo'] ?? ($rel . 'assets/images/logo.png');

    $name   = $cert['holder_name'] ?: ($user['name'] ?? 'Member');
    $biz    = trim((string)($cert['business_name'] ?? ''));
    $issued = date('d F Y', strtotime($cert['issued_on']));
    $valid  = !empty($cert['valid_till']) ? date('d F Y', strtotime($cert['valid_till'])) : '—';
    $no     = $cert['cert_no'];

    ob_start(); ?>
<div class="cred-wrap">
    <div class="cert-scroll">
        <div class="cert" id="credCert">
            <div class="cert-border"></div>
            <div class="cert-border2"></div>
            <div class="cert-corner tl"></div><div class="cert-corner tr"></div>
            <div class="cert-corner bl"></div><div class="cert-corner br"></div>
            <div class="cert-seal-bg"></div>

            <div class="cert-inner">
                <div class="cert-head">
                    <img src="<?php echo htmlspecialchars($logo); ?>" class="cert-logo" alt="" crossorigin="anonymous">
                    <div>
                        <div class="cert-brand"><?php echo htmlspecialchars(strtoupper($brand)); ?></div>
                        <div class="cert-tag">West Bengal Mini Cyber Zone</div>
                    </div>
                </div>

                <div class="cert-rule"></div>

                <div class="cert-title">
                    Certificate
                    <small>of Authorised Partnership</small>
                </div>

                <div class="cert-intro">This is to certify that</div>
                <div class="cert-name"><?php echo htmlspecialchars($name); ?></div>
                <?php if ($biz !== ''): ?>
                    <div class="cert-biz"><?php echo htmlspecialchars($biz); ?></div>
                <?php endif; ?>

                <div class="cert-body">
                    has been duly registered and recognised as an <b>Authorised Seller &amp; Service Partner</b>
                    of <?php echo htmlspecialchars(strtoupper($brand)); ?>, and is hereby permitted to offer and deliver
                    the approved range of digital services to customers in accordance with the
                    terms, standards and code of conduct of the organisation.
                </div>

                <div class="cert-foot">
                    <div class="cert-col">
                        <div class="cert-line"></div>
                        <div class="cert-k">Certificate No.</div>
                        <div class="cert-val"><?php echo htmlspecialchars($no); ?></div>
                    </div>

                    <div class="cert-seal">
                        <b>AUTHORISED<br>PARTNER</b>
                        <span><?php echo date('Y', strtotime($cert['issued_on'])); ?></span>
                    </div>

                    <div class="cert-col">
                        <div class="cert-line"></div>
                        <div class="cert-k">Authorised Signatory</div>
                        <div class="cert-val"><?php echo htmlspecialchars(strtoupper($brand)); ?></div>
                    </div>
                </div>

                <div style="display:flex;justify-content:space-between;font-size:8.5px;color:#9ca3af;letter-spacing:.09em;text-transform:uppercase;margin-top:14px;font-weight:700;">
                    <span>Issued on <?php echo htmlspecialchars($issued); ?></span>
                    <span>Member ID <?php echo htmlspecialchars(cred_member_id((int)$user['id'])); ?></span>
                    <span>Valid till <?php echo htmlspecialchars($valid); ?></span>
                </div>
            </div>
        </div>
    </div>

    <div class="flex flex-wrap gap-2 justify-center cred-noprint">
        <button type="button" class="cred-btn cred-btn-gold" onclick="credPdf('credCert','<?php echo htmlspecialchars(str_replace('/', '-', $no)); ?>', 297, 210)">
            <i class="fas fa-file-pdf"></i> Download PDF (A4)
        </button>
        <button type="button" class="cred-btn cred-btn-dark" onclick="credDownload('credCert','<?php echo htmlspecialchars(str_replace('/', '-', $no)); ?>')">
            <i class="fas fa-image"></i> Download PNG
        </button>
        <button type="button" class="cred-btn cred-btn-ghost" onclick="credPrint('credCert')">
            <i class="fas fa-print"></i> Print
        </button>
    </div>
</div>
<?php
    return ob_get_clean();
}

} // end function_exists guard
