<!DOCTYPE html>
<?php
/* Owner-only App Bundle page. Vars: $baseUrl, $assetsUrl, $user, $ownerName */
if (!isset($baseUrl)) $baseUrl = '';
if (!isset($assetsUrl)) $assetsUrl = rtrim($baseUrl, '/') . '/assets';
$dlUrl = rtrim($baseUrl, '/') . '/platform/app-bundle/download';
$curVer = \PpPhp\Core\Version::PLATFORM;
// Suggest the next patch version so a rebuild is recognised as a new release.
$vp = array_map('intval', explode('.', \PpPhp\Core\Version::normalise($curVer)));
$nextVer = $vp[0] . '.' . $vp[1] . '.' . ($vp[2] + 1);
?>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title><?= htmlspecialchars(\PpPhp\Core\Brand::name()) ?> · App Bundle</title>
    <?php include constant('BASE_PATH') . '/core/views/favicon.php'; ?>
    <link href="<?= $assetsUrl ?>/bootstrap/css/bootstrap.min.css" rel="stylesheet">
    <link href="<?= $assetsUrl ?>/icons/bootstrap-icons.css" rel="stylesheet">
    <?php include constant('BASE_PATH') . '/core/views/theme-head.php'; ?>
    <link href="<?= $assetsUrl ?>/sweetalert2/sweetalert2.min.css" rel="stylesheet">
    <script src="<?= $assetsUrl ?>/sweetalert2/sweetalert2.min.js"></script>
    <style>
        body { background: var(--pp-app-bg, #f5f6fa); color: var(--pp-text, #172033); }
        .ppb-topbar { background: var(--pp-surface, #fff); border-bottom: 1px solid var(--pp-border, #e6e9f0); }
        .ppb-wrap { max-width: 860px; margin: 2.2rem auto; padding: 0 1rem; }
        .ppb-editions { margin: 1.4rem 0 1.1rem; }
        .ppb-editions h3 { font-size: .95rem; font-weight: 800; margin: 0 0 .25rem; }
        .ppb-edition { display: flex; gap: .7rem; align-items: flex-start; cursor: pointer;
                       border: 1px solid var(--pp-border, #e6e9f0); border-radius: 12px;
                       padding: .85rem 1rem; height: 100%; transition: border-color .15s, background .15s; }
        .ppb-edition:hover { border-color: var(--pp-accent, #4f46e5); }
        .ppb-edition input { margin-top: .25rem; flex: none; }
        .ppb-edition:has(input:checked) { border-color: var(--pp-accent, #4f46e5);
                       background: color-mix(in srgb, var(--pp-accent, #4f46e5) 5%, transparent); }
        .ppb-card { background: var(--pp-surface, #fff); border: 1px solid var(--pp-border, #e6e9f0); border-radius: 16px; box-shadow: 0 8px 30px rgba(15,23,42,.06); overflow: hidden; }
        .ppb-head { padding: 1.4rem 1.6rem; background: linear-gradient(135deg, #4f46e5, #6366f1); color: #fff; }
        .ppb-owner { display: inline-flex; align-items: center; gap: .35rem; font-size: .72rem; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; background: rgba(255,255,255,.18); padding: .2rem .6rem; border-radius: 999px; }
        .ppb-body { padding: 1.6rem; }
        .ppb-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; margin: 1.1rem 0 1.3rem; }
        @media (max-width: 640px) { .ppb-grid { grid-template-columns: 1fr; } }
        .ppb-col h6 { font-size: .78rem; text-transform: uppercase; letter-spacing: .05em; color: var(--pp-muted, #64748b); margin-bottom: .5rem; }
        .ppb-col ul { list-style: none; padding: 0; margin: 0; font-size: .9rem; }
        .ppb-col li { display: flex; align-items: baseline; gap: .5rem; padding: .18rem 0; }
        .ppb-col.inc li i { color: #16a34a; } .ppb-col.exc li i { color: #dc2626; }
        .ppb-note { display: flex; gap: .6rem; align-items: flex-start; background: var(--pp-surface-soft, #f1f5f9); border: 1px solid var(--pp-border, #e2e8f0); border-radius: 12px; padding: .8rem 1rem; font-size: .86rem; color: var(--pp-muted, #475569); }
        .ppb-actions { display: flex; gap: .7rem; align-items: center; flex-wrap: wrap; margin-top: 1.3rem; }
    </style>
</head>
<body>
    <div class="ppb-topbar py-2">
        <div class="d-flex align-items-center px-3" style="max-width:1100px;margin:0 auto;">
            <a href="<?= $baseUrl ?>/projects" class="text-decoration-none d-flex align-items-center" style="color:inherit;">
                <?= \PpPhp\Core\Brand::lockup(32) ?>
            </a>
            <div class="ms-auto d-flex align-items-center gap-2"><?php include constant('BASE_PATH') . '/core/views/theme-toggle.php'; ?><a href="<?= $baseUrl ?>/projects" class="btn btn-sm btn-outline-secondary"><i class="bi bi-arrow-left me-1"></i>Back to Projects</a></div>
        </div>
    </div>

    <div class="ppb-wrap">
        <div class="ppb-card">
            <div class="ppb-head">
                <div class="d-flex align-items-start justify-content-between">
                    <div>
                        <div class="ppb-owner"><i class="bi bi-shield-lock-fill"></i> Owner only</div>
                        <h3 class="mt-2 mb-1"><i class="bi bi-box-seam me-2"></i>Download App Bundle</h3>
                        <p class="mb-0" style="opacity:.9;">Package this PPPHP platform as a <strong>Full Installer</strong> for a fresh install, or an <strong>Updates-only</strong> patch carrying just what changed.</p>
                    </div>
                </div>
            </div>
            <div class="ppb-body">
                <p class="text-muted mb-1">The bundle is built on demand, streamed to your browser, and then <strong>deleted from this server</strong> — no artifact is left behind. Deploy it by unzipping on the target server and opening <code>install.php</code>.</p>

                <div class="ppb-grid">
                    <div class="ppb-col inc">
                        <h6>Included</h6>
                        <ul>
                            <li><i class="bi bi-check-lg"></i> Full platform code + <code>vendor/</code> (runs out of the box)</li>
                            <li><i class="bi bi-check-lg"></i> <code>install.php</code> + <code>database.example.php</code></li>
                            <li><i class="bi bi-check-lg"></i> Empty writable folders (projects, output, storage)</li>
                        </ul>
                    </div>
                    <div class="ppb-col exc">
                        <h6>Excluded (kept private)</h6>
                        <ul>
                            <li><i class="bi bi-x-lg"></i> <code>config/database.php</code> (live DB credentials)</li>
                            <li><i class="bi bi-x-lg"></i> <code>projects/</code>, <code>output/</code> (your data + apps)</li>
                            <li><i class="bi bi-x-lg"></i> <code>storage/</code> (logs, backups, deploy keys)</li>
                        </ul>
                    </div>
                </div>

                <div class="ppb-note">
                    <i class="bi bi-shield-check fs-5" style="color:#16a34a;"></i>
                    <div>A built-in safety check re-scans the ZIP and refuses to produce it if any secret path would ship. The download begins automatically after packaging (a few seconds).</div>
                </div>

                <div class="ppb-editions">
                    <h3>Bundle type</h3>
                    <div class="row g-3">
                        <div class="col-md-6">
                            <label class="ppb-edition">
                                <input type="radio" name="ppType" value="full" checked>
                                <div>
                                    <strong><i class="bi bi-box-seam me-1"></i> Full Installer</strong>
                                    <div class="small text-muted mt-1">The complete platform — for a <strong>fresh install</strong>
                                        on a new server. Unzip and run <code>install.php</code>.</div>
                                </div>
                            </label>
                        </div>
                        <div class="col-md-6">
                            <label class="ppb-edition">
                                <input type="radio" name="ppType" value="updates">
                                <div>
                                    <strong><i class="bi bi-lightning-charge me-1"></i> Updates only (patch)</strong>
                                    <div class="small text-muted mt-1">Only the files <strong>changed since a previous
                                        version</strong> — a small file for existing installs / OTA hosting.</div>
                                </div>
                            </label>
                        </div>
                    </div>
                    <div id="ppFromWrap" class="mt-3" style="display:none">
                        <label class="small fw-bold d-block mb-1" for="ppFrom">Patch from version</label>
                        <select id="ppFrom" class="form-select" style="max-width:320px"></select>
                        <div id="ppFromEmpty" class="small text-muted mt-1" style="display:none">
                            No recorded baselines for this edition yet — build a <strong>Full Installer</strong> first, then
                            patches can diff against it.
                        </div>
                        <div class="small text-muted mt-1">The patch carries only what changed between that version and the
                            release version below.</div>
                    </div>
                </div>

                <div class="ppb-editions">
                    <h3>Which edition?</h3>
                    <p class="text-muted small mb-3">
                        The client edition is what you send to customers. It ships without the licence
                        authority and without the bundle builder — not hidden behind a role check, simply
                        not present, so a customer's install cannot issue licences to itself.
                    </p>
                    <div class="row g-3">
                        <div class="col-md-6">
                            <label class="ppb-edition">
                                <input type="radio" name="ppVariant" value="client" checked>
                                <div>
                                    <strong><i class="bi bi-people me-1"></i> Client edition</strong>
                                    <div class="small text-muted mt-1">For customers. Builds apps, activates
                                        against your licence server, applies updates.</div>
                                    <div class="small mt-2 text-success"><i class="bi bi-x-circle"></i> no licence
                                        issuing &nbsp;<i class="bi bi-x-circle"></i> no bundle builder</div>
                                </div>
                            </label>
                        </div>
                        <div class="col-md-6">
                            <label class="ppb-edition">
                                <input type="radio" name="ppVariant" value="server">
                                <div>
                                    <strong><i class="bi bi-key me-1"></i> Server edition</strong>
                                    <div class="small text-muted mt-1">For your own hosts — the primary licence
                                        service and its backup servers.</div>
                                    <div class="small mt-2 text-muted"><i class="bi bi-check-circle"></i> everything,
                                        licence authority included</div>
                                </div>
                            </label>
                        </div>
                    </div>
                </div>

                <div class="ppb-version">
                    <h3>Release version</h3>
                    <p class="text-muted small mb-2">
                        Installs compare this against what they already run to decide if a bundle is a new
                        update. Currently installed here: <code><?= htmlspecialchars($curVer) ?></code>.
                        <strong>Bump it for every release</strong> — otherwise the far side sees "same version"
                        and treats the upload as a no-op.
                    </p>
                    <input type="text" id="ppRelVer" class="form-control" style="max-width:220px"
                           value="<?= htmlspecialchars($nextVer) ?>" pattern="\d+\.\d+\.\d+"
                           placeholder="e.g. 1.0.1">
                    <div class="form-check mt-2">
                        <input class="form-check-input" type="checkbox" id="ppBumpSrc" checked>
                        <label class="form-check-label small text-muted" for="ppBumpSrc">
                            Also set <strong>this development copy</strong> to that version, so your dev build and your
                            servers stay in step (recommended).
                        </label>
                    </div>

                    <div class="form-check mt-3" id="ppProtectWrap">
                        <input class="form-check-input" type="checkbox" id="ppProtect">
                        <label class="form-check-label small" for="ppProtect">
                            <strong>Protected build</strong> — encrypt the build engine so it can only run with a valid
                            licence.
                            <span class="d-block text-muted mt-1">
                                The strongest protection available: instead of a licence <em>check</em> the customer could
                                edit out, the build engine ships encrypted and is unlocked by a key that travels inside
                                their signed licence. An unlicensed copy cannot run it at all. Mints a fresh key for this
                                release, so every customer must be online at least once to build after updating.
                                <strong>Customer (client) bundles only.</strong>
                            </span>
                        </label>
                    </div>
                </div>

                <div class="ppb-actions">
                    <a id="ppDlBundle" href="<?= htmlspecialchars($dlUrl) ?>" class="btn btn-primary btn-lg"><i class="bi bi-download me-2"></i>Generate &amp; Download</a>
                    <span class="text-muted small">Filename: <code>ppphp-&lt;edition&gt;-&lt;timestamp&gt;.zip</code></span>
                </div>
            </div>
        </div>
    </div>

    <script>
    (function () {
        var btn = document.getElementById('ppDlBundle');
        if (!btn) return;

        var BASELINES = <?= json_encode($baselines ?? ['client' => [], 'server' => []], JSON_UNESCAPED_SLASHES) ?>;
        var typeEls = document.querySelectorAll('input[name="ppType"]');
        var varEls  = document.querySelectorAll('input[name="ppVariant"]');
        var fromWrap = document.getElementById('ppFromWrap');
        var fromSel  = document.getElementById('ppFrom');
        var fromEmpty = document.getElementById('ppFromEmpty');
        var btnLabel = btn.querySelector('span') || btn;

        function selVariant() { var p = document.querySelector('input[name="ppVariant"]:checked'); return p ? p.value : 'client'; }
        function selType()    { var p = document.querySelector('input[name="ppType"]:checked'); return p ? p.value : 'full'; }

        function refresh() {
            // "Protected build" only applies to customer bundles — sealing our own
            // build engine would strand us if a lease ever lapsed.
            var prot = document.getElementById('ppProtect');
            var protWrap = document.getElementById('ppProtectWrap');
            if (prot && protWrap) {
                var allowed = selVariant() === 'client';
                prot.disabled = !allowed;
                if (!allowed) prot.checked = false;
                protWrap.style.opacity = allowed ? '1' : '.5';
            }

            var isUpd = selType() === 'updates';
            fromWrap.style.display = isUpd ? '' : 'none';
            btn.innerHTML = '<i class="bi bi-download me-2"></i>' + (isUpd ? 'Generate patch' : 'Generate & Download');
            if (!isUpd) return;
            var list = BASELINES[selVariant()] || [];
            fromSel.innerHTML = list.map(function (b) {
                return '<option value="' + b.version + '">' + b.version +
                    (b.source === 'published' ? '  (published)' : '') + '</option>';
            }).join('');
            var none = list.length === 0;
            fromSel.style.display = none ? 'none' : '';
            fromEmpty.style.display = none ? '' : 'none';
        }
        typeEls.forEach(function (el) { el.addEventListener('change', refresh); });
        varEls.forEach(function (el) { el.addEventListener('change', refresh); });
        refresh();

        btn.addEventListener('click', function (e) {
            e.preventDefault();
            var type = selType();
            if (type === 'updates' && (!fromSel.value)) {
                Swal.fire({ icon: 'info', title: 'Pick a baseline',
                    text: 'Build a Full Installer of a prior version first, then choose it as the version to patch from.' });
                return;
            }
            var token = 'b' + Date.now();
            var base = btn.getAttribute('href');
            var variant = selVariant();
            var relver = (document.getElementById('ppRelVer') || {}).value || '';
            var bumpSrc = (document.getElementById('ppBumpSrc') || {}).checked ? '1' : '0';
            var protect = (document.getElementById('ppProtect') || {}).checked && variant === 'client' ? '1' : '0';
            var url = base + (base.indexOf('?') > -1 ? '&' : '?') + 'token=' + token + '&variant=' + variant
                    + '&type=' + type + (type === 'updates' ? '&from=' + encodeURIComponent(fromSel.value) : '')
                    + (relver ? '&relver=' + encodeURIComponent(relver.trim()) + '&bumpsrc=' + bumpSrc : '')
                    + (protect === '1' ? '&protect=1' : '');
            Swal.fire({
                title: 'Preparing your bundle…',
                html: 'Packaging the platform and running the safety check.<br>This can take a few seconds.',
                allowOutsideClick: false, allowEscapeKey: false,
                didOpen: function () { Swal.showLoading(); }
            });
            // Download via a hidden iframe so the page stays put and errors stay contained.
            var ifr = document.getElementById('ppDlFrame');
            if (!ifr) { ifr = document.createElement('iframe'); ifr.id = 'ppDlFrame'; ifr.style.display = 'none'; document.body.appendChild(ifr); }
            ifr.src = url;
            // Cookie handshake: the server sets pp_bundle_ready=<token> right before streaming.
            var tries = 0;
            var iv = setInterval(function () {
                tries++;
                if (document.cookie.indexOf('pp_bundle_ready=' + token) > -1) {
                    clearInterval(iv);
                    document.cookie = 'pp_bundle_ready=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/';
                    Swal.fire({ icon: 'success', title: 'Bundle ready', text: 'Your download has started. The file was removed from the server automatically.', timer: 3800, showConfirmButton: false });
                } else if (tries > 240) {   // ~120s safety net
                    clearInterval(iv);
                    Swal.close();
                }
            }, 500);
        });
    })();
    </script>
</body>
</html>
