// Per-app backup card — used inside the app detail "Backups" tab.
// Lightweight view that lists the app's snapshots across all enabled repos and
// offers Backup Now + per-snapshot restore. For full management (delete,
// migrate, schedule overrides) the user follows the link to /backup.

class BackupAppCard {
    constructor(appName) {
        this.appName = appName;
        this.snapshotsByLoc = {};
        this.locationsByIdx = {};
        this.appStatus = null;
        this.taskManager = (typeof TaskManager !== 'undefined') ? new TaskManager() : null;
        this.bindDelegated();
    }

    bindDelegated() {
        if (window.__backupAppCardBound) return;
        window.__backupAppCardBound = true;

        document.addEventListener('click', (e) => {
            const card = window.backupAppCard;
            if (!card) return;

            if (e.target.closest('#backup-app-card-backup-btn')) {
                card.backupNow();
                return;
            }

            const restoreBtn = e.target.closest('[data-action="restore-app-snapshot"]');
            if (restoreBtn) {
                card.restoreSnapshot(restoreBtn.dataset.loc, restoreBtn.dataset.snapshot);
            }
        });
    }

    async render() {
        const statusEl = document.getElementById('backup-app-card-status');
        const snapsEl = document.getElementById('backup-app-card-snapshots');
        if (!statusEl || !snapsEl) return;

        statusEl.textContent = 'Loading…';
        snapsEl.innerHTML = '';

        await this.loadData();

        const allSnaps = this.flattenSnapshots();
        if (!allSnaps.length) {
            statusEl.innerHTML = `<span class="backup-status-dot none"></span> No snapshots yet`;
            snapsEl.innerHTML = `<div class="backup-empty-state">No snapshots found for <strong>${this.escape(this.appName)}</strong>. Click "Backup now" to create the first one.</div>`;
            return;
        }

        const latest = allSnaps[0];
        const locCount = Object.keys(this.snapshotsByLoc).length;
        statusEl.innerHTML = `
            <span class="backup-status-dot ok"></span>
            Latest backup ${this.formatRelative(latest.time)}
            <span class="backup-card-hint">${allSnaps.length} total across ${locCount} location${locCount === 1 ? '' : 's'}</span>
        `;

        snapsEl.innerHTML = `
            <table class="backup-snapshot-table" style="margin-top:14px">
                <thead>
                    <tr>
                        <th>Location</th>
                        <th>When</th>
                        <th>ID</th>
                        <th class="backup-col-actions"></th>
                    </tr>
                </thead>
                <tbody>
                    ${allSnaps.slice(0, 15).map(s => `
                        <tr>
                            <td>${this.escape(s.locName)}</td>
                            <td>${this.formatRelative(s.time)}</td>
                            <td class="backup-snapshot-id">${this.escape(s.id)}</td>
                            <td class="backup-col-actions">
                                <button class="backup-row-action-btn" data-action="restore-app-snapshot" data-loc="${s.locIdx}" data-snapshot="${this.escape(s.id)}">Restore</button>
                            </td>
                        </tr>
                    `).join('')}
                </tbody>
            </table>
        `;
    }

    async loadData() {
        const ts = Date.now();
        const statusUrl = `/data/backup/generated/apps/${encodeURIComponent(this.appName)}.json?t=${ts}`;
        const locationsUrl = `/data/backup/generated/locations.json?t=${ts}`;

        const [appStatus, locationsJson] = await Promise.all([
            this.fetchJson(statusUrl),
            this.fetchJson(locationsUrl)
        ]);
        this.appStatus = appStatus;
        this.snapshotsByLoc = {};
        this.locationsByIdx = {};

        if (locationsJson?.locations?.length) {
            locationsJson.locations.forEach(l => { this.locationsByIdx[l.idx] = l; });
            const enabled = locationsJson.locations.filter(l => l.enabled);
            await Promise.all(enabled.map(async (l) => {
                const data = await this.fetchJson(`/data/backup/generated/snapshots_${l.idx}.json?t=${ts}`);
                if (data?.snapshots) this.snapshotsByLoc[l.idx] = data.snapshots;
            }));
        }
    }

    flattenSnapshots() {
        const out = [];
        Object.entries(this.snapshotsByLoc).forEach(([locIdx, snaps]) => {
            (snaps || []).forEach(s => {
                const tags = s.tags || [];
                const isApp = tags.includes(`app=${this.appName}`);
                if (!isApp) return;
                out.push({
                    locIdx,
                    locName: this.locationsByIdx[locIdx]?.name || `Location ${locIdx}`,
                    time: s.time,
                    id: s.short_id || (s.id || '').slice(0, 8)
                });
            });
        });
        out.sort((a, b) => String(b.time).localeCompare(String(a.time)));
        return out;
    }

    async fetchJson(url) {
        try {
            const r = await fetch(url);
            if (!r.ok) return null;
            return await r.json();
        } catch { return null; }
    }

    async backupNow() {
        if (!this.taskManager) return;
        await this.taskManager.createTask(`libreportal backup app create ${this.appName}`, 'backup', this.appName);
        setTimeout(() => this.render(), 1500);
    }

    async restoreSnapshot(locIdx, snapshot) {
        const locName = this.locationsByIdx[locIdx]?.name || `Location ${locIdx}`;
        if (!confirm(`Restore ${this.appName} from backup ${snapshot} at ${locName}? The app will be stopped, its folder wiped, the backup restored in place, then the app started again.`)) return;
        if (!this.taskManager) return;
        await this.taskManager.createTask(`libreportal restore app start ${this.appName} ${snapshot} ${locIdx}`, 'restore', this.appName);
    }

    escape(s) {
        return String(s ?? '').replace(/[&<>"']/g, c => ({
            '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;'
        })[c]);
    }

    formatRelative(iso) {
        if (!iso) return '—';
        const t = new Date(iso).getTime();
        if (!t) return iso;
        const diff = Math.max(0, Date.now() - t);
        const s = Math.floor(diff / 1000);
        if (s < 60)  return 'just now';
        const m = Math.floor(s / 60);
        if (m < 60)  return `${m}m ago`;
        const h = Math.floor(m / 60);
        if (h < 48)  return `${h}h ago`;
        const d = Math.floor(h / 24);
        if (d < 30)  return `${d}d ago`;
        return new Date(iso).toLocaleDateString();
    }
}

window.BackupAppCard = BackupAppCard;
