// Auto-extracted from backup-page.js (verbatim) — augments BackupPage.prototype. Loaded after the base.
Object.assign(BackupPage.prototype, {
    renderSnapshots() {
        const list = document.getElementById('backup-snapshot-list');
        if (!list) return;

        const filter = (document.getElementById('backup-snapshot-filter')?.value || '').toLowerCase();
        const locFilter = document.getElementById('backup-snapshot-repo')?.value || '';

        const locNameByIdx = {};
        (this.locations?.locations || []).forEach(l => { locNameByIdx[l.idx] = l.name; });

        const rows = [];
        Object.entries(this.snapshotsByLoc).forEach(([locIdx, data]) => {
            if (locFilter && String(locFilter) !== String(locIdx)) return;
            const snaps = Array.isArray(data?.snapshots) ? data.snapshots : [];
            snaps.forEach(s => {
                const app = (s.tags || []).map(t => /^app=/.test(t) ? t.slice(4) : null).find(Boolean) || '—';
                rows.push({
                    app,
                    host: s.hostname || '—',
                    locIdx,
                    locName: locNameByIdx[locIdx] || `Loc ${locIdx}`,
                    time: s.time,
                    id: s.short_id || (s.id || '').slice(0, 8),
                    tags: Array.isArray(s.tags) ? s.tags : [],
                    paths: Array.isArray(s.paths) ? s.paths : [],
                });
            });
        });

        rows.sort((a, b) => String(b.time).localeCompare(String(a.time)));

        const filtered = filter ? rows.filter(r =>
            r.app.toLowerCase().includes(filter) ||
            r.host.toLowerCase().includes(filter) ||
            r.id.toLowerCase().includes(filter) ||
            r.locName.toLowerCase().includes(filter)
        ) : rows;

        if (!filtered.length) {
            list.innerHTML = `<div class="backup-empty-state">No backups yet.</div>`;
            return;
        }

        list.innerHTML = filtered.map(r => this._renderSnapshotRow(r)).join('');
    },
    // Render one global-Snapshots-tab backup as the same .task-item card
    // the per-app Backups tab uses, so the two surfaces look identical.
    // Extras vs the per-app card:
    //   - An app-name chip (because the global list isn't scoped to one app)
    //     that doubles as a deep-link to /app/<name>/backups?snapshot=<id>
    //   - A Delete action alongside Restore (per-app card only offers
    //     Restore — delete lives in the global view)
    _renderSnapshotRow(r) {
        const hasApp = r.app && r.app !== '—';
        const deepLink = hasApp
            ? `/app/${encodeURIComponent(r.app)}/backups?snapshot=${encodeURIComponent(r.id)}`
            : null;
        const iconUrl = hasApp ? `/core/icons/apps/${encodeURIComponent(r.app)}.svg` : '/core/icons/apps/libreportal.svg';
        const displayName = hasApp ? this.appMeta(r.app).displayName : 'Configs';
        const appChip = hasApp
            ? `<a class="backup-snapshot-link backup-snapshot-app-chip" href="${this.escape(deepLink)}" data-deep-link="${this.escape(deepLink)}" title="Open ${this.escape(displayName)} backups">${this.escape(displayName)}</a>`
            : `<span class="backup-snapshot-app-chip">${this.escape(displayName)}</span>`;
        const sid = String(r.id);

        // Restic stamps app=/host=/engine= into the snapshot tags; surface
        // those as their own fields and keep any remaining tags as chips.
        const tagMap = {};
        (r.tags || []).forEach(t => { const i = t.indexOf('='); if (i > 0) tagMap[t.slice(0, i)] = t.slice(i + 1); });
        const engineName = tagMap.engine ? this.engineDisplayName(tagMap.engine) : null;
        const otherTags = (r.tags || []).filter(t => !/^(app|host|engine|paths?)=/.test(t));
        const field = (label, valueHtml) =>
            `<div class="bsm-field"><span class="bsm-label">${label}</span><span class="bsm-value">${valueHtml}</span></div>`;

        return `
            <div class="task-item backup-snapshot-item" data-snapshot="${this.escape(sid)}" data-loc="${this.escape(String(r.locIdx))}">
                <div class="task-header" data-action="toggle-snapshot-row">
                    <div class="task-info">
                        <img src="${this.escape(iconUrl)}" alt="" class="task-app-icon" onerror="this.style.display='none'">
                        <span class="task-title">${this.escape(this.formatRelative(r.time))}</span>
                        ${appChip}
                        <span class="task-status backup-snapshot-loc-pill">${this.escape(r.locName)}</span>
                        <span class="task-time" title="${this.escape(this._fmtFullTime(r.time))}">${this.escape(this._fmtShortTime(r.time))}</span>
                        <span class="backup-snapshot-id-chip" title="Backup ID">${this.escape(sid)}</span>
                    </div>
                    <div class="task-actions">
                        <button class="task-btn" data-action="restore-snapshot" data-app="${this.escape(r.app)}" data-loc="${this.escape(String(r.locIdx))}" data-snapshot="${this.escape(sid)}" title="Restore from this backup">
                            <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 12a9 9 0 1 0 3-6.7"/><path d="M3 4v6h6"/></svg>
                            <span class="task-btn-label">Restore</span>
                        </button>
                        <button class="task-btn delete" data-action="delete-snapshot" data-app="${this.escape(r.app)}" data-loc="${this.escape(String(r.locIdx))}" data-snapshot="${this.escape(sid)}" title="Delete this backup">
                            <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="3 6 5 6 21 6"></polyline><path d="M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"></path><path d="M10 11v6M14 11v6"></path></svg>
                            <span class="task-btn-label">Delete</span>
                        </button>
                        <button class="task-btn toggle-details" data-action="toggle-snapshot-row" title="Toggle details">
                            <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="6,9 12,15 18,9"></polyline></svg>
                            <span class="task-btn-label">Details</span>
                        </button>
                    </div>
                </div>
                <div class="task-details">
                    <div class="backup-snapshot-meta">
                        <div class="bsm-grid">
                            ${field('App', `${this.escape(displayName)}${hasApp ? ` <code>${this.escape(r.app)}</code>` : ''}`)}
                            ${field('Host', this.escape(r.host))}
                            ${field('Location', `<span class="backup-snapshot-loc-pill">${this.escape(r.locName)}</span>`)}
                            ${field('Backup ID', `<code>${this.escape(sid)}</code>`)}
                            ${field('When', `<span title="${this.escape(this._fmtFullTime(r.time))}">${this.escape(this._fmtNiceTime(r.time))}</span>`)}
                            ${engineName ? field('Engine', this.escape(engineName)) : ''}
                        </div>
                        ${otherTags.length ? `
                        <div class="bsm-block">
                            <span class="bsm-label">Tags</span>
                            <div class="bsm-tags">${otherTags.map(t => `<span class="backup-snapshot-tag">${this.escape(t)}</span>`).join('')}</div>
                        </div>` : ''}
                        ${r.paths && r.paths.length ? `
                        <div class="bsm-block">
                            <span class="bsm-label">Paths</span>
                            <ul class="bsm-paths">${r.paths.map(p => `<li><code>${this.escape(p)}</code></li>`).join('')}</ul>
                        </div>` : ''}
                    </div>
                </div>
            </div>`;
    },
    _fmtShortTime(iso) {
        if (!iso) return '';
        const d = new Date(iso);
        if (isNaN(d.getTime())) return String(iso);
        return d.toLocaleString();
    },
    _fmtFullTime(iso) {
        if (!iso) return '';
        const d = new Date(iso);
        if (isNaN(d.getTime())) return String(iso);
        return d.toString();
    },
    _fmtNiceTime(iso) {
        if (!iso) return '';
        const d = new Date(iso);
        if (isNaN(d.getTime())) return String(iso);
        return d.toLocaleString(undefined, { dateStyle: 'medium', timeStyle: 'short' });
    },
});
