// Admin → System → Storage — Docker disk-usage breakdown.
//
// Mounted at /admin/config/system/storage. Visualises `docker system df`:
//
//   - Headline total + reclaimable
//   - Donut chart split by category (images / containers / volumes / build cache)
//   - Per-category cards (count + size + reclaimable)
//   - Top 10 images by size
//   - Top 10 volumes by size
//
// One backend call (GET /api/system/storage), cached server-side for 5s.
// No actions yet — purely informational. Prune controls deferred to a v2.

class SystemStoragePage {
    constructor(rootId = 'config-section') {
        this.rootId = rootId;
        this.data = null;
        this._timer = null;
        this._onClick = this._onClick.bind(this);
    }

    root() { return document.getElementById(this.rootId); }

    async mount() {
        this._renderShell();
        await this._load();
        this._render();
        const r = this.root();
        if (r) r.addEventListener('click', this._onClick);
        // Refresh every 30s while mounted.
        this._timer = setInterval(() => {
            if (!document.querySelector('.sys-storage-page')) {
                clearInterval(this._timer); this._timer = null;
                return;
            }
            this._load().then(() => this._render());
        }, 30000);
    }

    dispose() {
        if (this._timer) { clearInterval(this._timer); this._timer = null; }
        const r = this.root();
        if (r) r.removeEventListener('click', this._onClick);
    }

    _onClick(e) {
        const back = e.target.closest('[data-back]');
        if (back && window.navigateToRoute) {
            window.navigateToRoute('/admin/config/system');
        }
    }

    async _load() {
        try {
            const r = await fetch('/api/system/storage');
            const j = await r.json().catch(() => null);
            this.data = j || null;
        } catch (_) {
            this.data = null;
        }
    }

    _renderShell() {
        const r = this.root();
        if (!r) return;
        r.innerHTML = `
            <div class="admin-page sys-storage-page">
                <div class="page-header config-page-header">
                    <div class="page-header-title">
                        <div class="admin-breadcrumb">
                            <a href="/admin/config/system" data-back>Admin · System</a>
                        </div>
                        <h1>Storage</h1>
                        <p class="sys-storage-sub">Docker disk usage — images, containers, volumes, and build cache.</p>
                    </div>
                </div>
                <div class="sys-storage-body" data-storage-body>
                    <div class="sys-storage-loading">Reading Docker daemon…</div>
                </div>
            </div>`;
    }

    _render() {
        const r = this.root();
        if (!r) return;
        const body = r.querySelector('[data-storage-body]');
        if (!body) return;
        const d = this.data;
        if (!d) {
            body.innerHTML = `<div class="sys-storage-err">Couldn't read disk usage from the Docker daemon.</div>`;
            return;
        }
        const fmt = window.SystemFmt;
        const segments = [
            { key: 'images',      label: 'Images',      color: 'accent',         data: d.images || {} },
            { key: 'volumes',     label: 'Volumes',     color: 'status-success', data: d.volumes || {} },
            { key: 'containers',  label: 'Containers',  color: 'status-info',    data: d.containers || {} },
            { key: 'build_cache', label: 'Build cache', color: 'status-warning', data: d.build_cache || {} },
        ];
        const total = d.total || 1;
        const recl = d.reclaimable || 0;
        const reclPct = total ? (recl / total) * 100 : 0;

        // Donut: cumulative segment arcs, full circle = total. Hand-rolled
        // SVG. Stroke-dasharray + stroke-dashoffset for each slice.
        const r0 = 90;            // ring radius
        const stroke = 28;
        const C = 2 * Math.PI * r0;
        let acc = 0;
        const slices = segments.map(s => {
            const v = s.data.size || 0;
            const frac = total > 0 ? v / total : 0;
            const len = C * frac;
            const off = C * (1 - acc);   // rotated offset start
            acc += frac;
            return { ...s, frac, len, off };
        });

        const donut = `
            <svg viewBox="0 0 240 240" class="sys-storage-donut" role="img" aria-label="Storage breakdown">
                <g transform="translate(120 120) rotate(-90)">
                    <circle cx="0" cy="0" r="${r0}" fill="none" stroke="rgba(var(--text-rgb), 0.08)" stroke-width="${stroke}"/>
                    ${slices.map(s => s.len > 0
                        ? `<circle cx="0" cy="0" r="${r0}" fill="none"
                                  stroke="var(--${s.color})" stroke-width="${stroke}"
                                  stroke-dasharray="${s.len.toFixed(1)} ${(C - s.len).toFixed(1)}"
                                  stroke-dashoffset="${(-((acc - s.frac) * C - 0)).toFixed(1)}"
                                  style="transition:stroke-dasharray .4s ease"/>`
                        : ''
                    ).join('')}
                </g>
                <text x="120" y="115" text-anchor="middle" class="sys-storage-donut-total">${fmt.bytes(total)}</text>
                <text x="120" y="138" text-anchor="middle" class="sys-storage-donut-sub">total in use</text>
            </svg>`;

        const legend = `
            <ul class="sys-storage-legend">
                ${segments.map(s => `
                    <li>
                        <span class="sys-storage-swatch" style="background: var(--${s.color})"></span>
                        <span class="sys-storage-leg-k">${s.label}</span>
                        <span class="sys-storage-leg-v">${fmt.bytes(s.data.size || 0)}</span>
                        ${s.data.reclaimable ? `<span class="sys-storage-leg-r">${fmt.bytes(s.data.reclaimable)} reclaimable</span>` : ''}
                    </li>`).join('')}
            </ul>`;

        const headline = `
            <div class="sys-storage-headline">
                <div class="sys-storage-head-card">
                    ${donut}
                    ${legend}
                </div>
                <div class="sys-storage-head-stats">
                    <div class="sys-storage-stat">
                        <span class="sys-storage-stat-k">Total in use</span>
                        <strong class="sys-storage-stat-v">${fmt.bytes(total)}</strong>
                    </div>
                    <div class="sys-storage-stat sys-storage-stat-recl">
                        <span class="sys-storage-stat-k">Reclaimable</span>
                        <strong class="sys-storage-stat-v">${fmt.bytes(recl)}</strong>
                        <span class="sys-storage-stat-sub">${reclPct.toFixed(0)}% of total · stopped containers, dangling images, unused volumes &amp; cache</span>
                    </div>
                </div>
            </div>`;

        const catCards = `
            <div class="sys-section-head"><h2>Categories</h2></div>
            <div class="sys-storage-cards">
                ${segments.map(s => {
                    const v = s.data || {};
                    const pct = v.size && total ? (v.size / total) * 100 : 0;
                    const reclPct = v.size ? (v.reclaimable / v.size) * 100 : 0;
                    return `
                        <div class="sys-storage-card" style="--cat: var(--${s.color}); --cat-rgb: var(--${s.color}-rgb)">
                            <div class="sys-storage-card-head">
                                <h3>${s.label}</h3>
                                <span class="sys-storage-card-count">${v.count ?? 0}</span>
                            </div>
                            <div class="sys-storage-card-size">${fmt.bytes(v.size || 0)}</div>
                            <div class="sys-storage-card-bar"><span style="width:${pct.toFixed(1)}%"></span></div>
                            <div class="sys-storage-card-meta">
                                <span>${pct.toFixed(1)}% of total</span>
                                ${v.reclaimable
                                    ? `<span class="sys-storage-card-recl">${fmt.bytes(v.reclaimable)} reclaimable (${reclPct.toFixed(0)}%)</span>`
                                    : ''}
                            </div>
                        </div>`;
                }).join('')}
            </div>`;

        const topImages = Array.isArray(d.top_images) ? d.top_images : [];
        const topVolumes = Array.isArray(d.top_volumes) ? d.top_volumes : [];

        const imagesTable = topImages.length ? `
            <div class="sys-section-head"><h2>Largest images</h2><span class="sys-chart-meta">top ${topImages.length} by size</span></div>
            <div class="sys-apps-wrap">
                <table class="sys-apps">
                    <thead><tr><th>Tag</th><th>Size</th><th>Shared</th><th>Containers</th><th>Created</th></tr></thead>
                    <tbody>
                        ${topImages.map(im => `
                            <tr>
                                <td class="sys-app-name">${fmt.escape((im.repo_tags && im.repo_tags[0]) || im.id?.slice(0, 19) || '—')}</td>
                                <td>${fmt.bytes(im.size)}</td>
                                <td>${fmt.bytes(im.shared_size || 0)}</td>
                                <td>${im.containers}${im.containers === 0 ? ' <span class="sys-storage-orphan">unused</span>' : ''}</td>
                                <td>${im.created ? fmt.timeAgo(im.created) : '—'}</td>
                            </tr>`).join('')}
                    </tbody>
                </table>
            </div>` : '';

        const volumesTable = topVolumes.length ? `
            <div class="sys-section-head"><h2>Largest volumes</h2><span class="sys-chart-meta">top ${topVolumes.length} by size</span></div>
            <div class="sys-apps-wrap">
                <table class="sys-apps">
                    <thead><tr><th>Name</th><th>Driver</th><th>Size</th><th>Refs</th></tr></thead>
                    <tbody>
                        ${topVolumes.map(v => `
                            <tr>
                                <td class="sys-app-name">${fmt.escape(v.name)}</td>
                                <td>${fmt.escape(v.driver || '—')}</td>
                                <td>${fmt.bytes(v.size)}</td>
                                <td>${v.ref_count}${v.ref_count === 0 ? ' <span class="sys-storage-orphan">orphan</span>' : ''}</td>
                            </tr>`).join('')}
                    </tbody>
                </table>
            </div>` : '';

        body.innerHTML = `${headline}${catCards}${imagesTable}${volumesTable}`;
    }
}

window.SystemStoragePage = SystemStoragePage;
