---
// HomelabStatus.astro
// Set USE_DEMO=false and API_URL to your actual endpoint once deployed.
---

<section class="section homelab-status" id="homelab-status">
  <div class="container">
    <div class="hl-header">
      <div>
        <div class="accent-line"></div>
        <h2>Homelab <span class="text-accent">Status</span></h2>
        <p class="font-mono text-muted" style="font-size:0.82rem;margin-top:0.4rem">
          Proxmox · pve-node-01 ·
          <span id="hl-ts" class="text-accent" style="font-size:0.75rem">connecting...</span>
        </p>
      </div>
      <a href="/homelab" class="btn btn-primary">Full overview →</a>
    </div>

    <div class="hl-grid" id="hl-grid">
      <div class="hl-card skeleton"></div>
      <div class="hl-card skeleton"></div>
      <div class="hl-card skeleton"></div>
      <div class="hl-card skeleton"></div>
    </div>

    <div class="hl-detail card" id="hl-detail" style="margin-top:1.5rem;display:none">
      <div class="hl-detail-grid">
        <div class="hl-spark-block">
          <span class="hl-spark-label font-mono">CPU history (1 min)</span>
          <div class="spark-bars" id="bars-cpu"></div>
        </div>
        <div class="hl-spark-block">
          <span class="hl-spark-label font-mono">Load history (1 min)</span>
          <div class="spark-bars" id="bars-load"></div>
        </div>
        <div class="hl-spark-block">
          <span class="hl-spark-label font-mono">Network RX/TX (1 min)</span>
          <div class="spark-bars" id="bars-net"></div>
        </div>
      </div>
    </div>
  </div>
</section>

<script is:inline>
// ── CONFIG ────────────────────────────────────────────────────────────
const API_URL  = 'http://pve.int:8080/api/homelab'; // Or use raw IP
const SPARK_H  = 48; // Pixel height of .spark-bars

// ── FALLBACK ROLLING BUFFERS ──────────────────────────────────────────
let fallbackCpu  = Array(60).fill(0);
let fallbackLoad = Array(60).fill(0);
let fallbackRx   = Array(60).fill(0);
let fallbackTx   = Array(60).fill(0);

// ── DATA PARSER ───────────────────────────────────────────────────────
function parseData(d, isLive, timestamp = null) {
  const cCpu  = Math.round(d.cpu || 0);
  const cRam  = Math.round(d.ram?.percent ?? d.ram ?? 0);
  const cLoad = d.load_avg ? d.load_avg[0] : 0;
  const cRx   = d.rx_mb || 0;
  const cTx   = d.tx_mb || 0;

  function roll(buf, hist, val) {
    if (hist && hist.length > 0) return hist;
    buf.shift(); buf.push(val);
    return [...buf];
  }

  return {
    isLive,
    timestamp,
    cpu:       cCpu,
    ram_used:  cRam,
    root_disk: Math.round(d.root_disk_pct || 0),
    rx_mb:     cRx,
    tx_mb:     cTx,
    cpu_hist:  roll(fallbackCpu,  d.cpu_hist,  cCpu),
    load_hist: roll(fallbackLoad, d.load_hist, cLoad),
    rx_hist:   roll(fallbackRx,   d.rx_hist,   cRx),
    tx_hist:   roll(fallbackTx,   d.tx_hist,   cTx),
  };
}

// ── CACHED FETCH LOGIC ────────────────────────────────────────────────
async function fetchLive() {
  try {
    // 1. Try to fetch the live data
    const res = await fetch(API_URL, { signal: AbortSignal.timeout(4000) });
    const d   = await res.json();
    if (d.error) throw new Error(d.error);

    // 2. If successful, save it to the browser's Local Storage!
    localStorage.setItem('homelab_cache', JSON.stringify(d));
    localStorage.setItem('homelab_ts', Date.now());

    return parseData(d, true);

  } catch (e) {
    console.warn('API fetch failed, attempting to load from cache...', e);
    
    // 3. If it fails, pull the last known good data from memory
    const cachedData = localStorage.getItem('homelab_cache');
    const cachedTime = localStorage.getItem('homelab_ts');
    
    if (cachedData) {
      return parseData(JSON.parse(cachedData), false, parseInt(cachedTime));
    } else {
      throw new Error("No cache available and API is offline.");
    }
  }
}

// ── RENDER ────────────────────────────────────────────────────────────
function bar(pct) {
  const c = pct > 85 ? '#FF4444' : pct > 70 ? '#FFB800' : '#00D2BE';
  return `<div class="hl-bar-track"><div class="hl-bar-fill" style="width:${pct}%;background:${c}"></div></div>`;
}

function renderCards(d) {
  const cards = [
    { label: 'CPU',     value: `${d.cpu}%`,                    sub: 'overall usage',      pct: d.cpu,       icon: '⬡' },
    { label: 'RAM',     value: `${d.ram_used}%`,               sub: 'used of total',      pct: d.ram_used,  icon: '▣' },
    { label: 'Disk',    value: `${d.root_disk}%`,              sub: '/ partition usage',  pct: d.root_disk, icon: '⛁' },
    { label: 'Network', value: `↓${d.rx_mb} ↑${d.tx_mb}`,    sub: 'Mbps rx / tx',       pct: null,        icon: '⇅' },
  ];

  const grid = document.getElementById('hl-grid');
  if (grid) {
    grid.innerHTML = cards.map(c => `
      <div class="hl-card card ${d.isLive ? '' : 'offline-card'}">
        <div class="hl-card-top">
          <span class="hl-icon">${c.icon}</span>
          <span class="hl-label font-mono">${c.label}</span>
        </div>
        <div class="hl-value font-display">${c.value}</div>
        <div class="hl-sub text-muted">${c.sub}</div>
        ${c.pct !== null ? bar(c.pct) : ''}
      </div>
    `).join('');
  }
}

function renderSparks(d) {
  document.getElementById('hl-detail').style.display = '';
  renderSparkBars('bars-cpu', d.cpu_hist, '#00D2BE');
  renderSparkBars('bars-load', d.load_hist, '#00A19C');
  renderSparkBars('bars-net', d.rx_hist,  '#007A76', d.tx_hist);
}

// BULLETPROOF SVG RENDERER
function renderSparkBars(id, series, color, series2) {
  const el = document.getElementById(id);
  if (!el || !series.length) return;
  
  const W = 240; 
  const H = SPARK_H;
  const max = Math.max(...series, ...(series2 || []), 0.05);
  
  let rects = '';
  const step = W / series.length; 
  const barW = series2 ? 1.5 : 3; 

  series.forEach((v, i) => {
    const x = i * step; 
    const h1 = Math.max(1, (v / max) * H); 
    const y1 = H - h1;

    if (series2) {
      const h2 = Math.max(1, ((series2[i] || 0) / max) * H);
      const y2 = H - h2;
      rects += `<rect x="${x}" y="${y1}" width="${barW}" height="${h1}" fill="${color}" opacity="0.9"/>`;
      rects += `<rect x="${x + barW}" y="${y2}" width="${barW}" height="${h2}" fill="#005F5D" opacity="0.7"/>`;
    } else {
      rects += `<rect x="${x}" y="${y1}" width="${barW}" height="${h1}" fill="${color}"/>`;
    }
  });

  el.innerHTML = `<svg viewBox="0 0 ${W} ${H}" preserveAspectRatio="none" style="width:100%; height:${H}px; display:block; ${series2 ? '' : 'opacity: 0.8;'}">${rects}</svg>`;
}

async function render() {
  const ts = document.getElementById('hl-ts');
  try {
    const data = await fetchLive();
    renderCards(data);
    renderSparks(data);
    
    // Update the timestamp based on live/offline status
    if (data.isLive) {
      ts.style.color = 'var(--petronas-teal)';
      ts.textContent = 'updated ' + new Date().toLocaleTimeString('en-GB', { hour: '2-digit', minute: '2-digit', second: '2-digit' });
    } else {
      ts.style.color = '#FFB800'; // Warning Orange
      const oldTime = new Date(data.timestamp).toLocaleTimeString('en-GB', { hour: '2-digit', minute: '2-digit', second: '2-digit' });
      ts.textContent = `offline · last seen ${oldTime}`;
    }
  } catch (e) {
    // Only happens if the API is dead AND there is no cache
    if (ts) {
      ts.style.color = '#FF4444'; // Error Red
      ts.textContent = 'API unreachable · no cache found';
    }
  }
}

render();
// refresh every 10 sec 
setInterval(render, 10000);
</script>

<style>
  .homelab-status { padding-top: 4rem; }

  .hl-header {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    margin-bottom: 2.5rem;
    gap: 1rem;
    flex-wrap: wrap;
  }

  .hl-grid {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 1.25rem;
  }

  .hl-card {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    min-height: 130px;
    transition: opacity 0.3s ease;
  }
  
  /* Make cards look slightly faded when offline */
  .offline-card {
    opacity: 0.6;
    filter: grayscale(40%);
  }

  .hl-card.skeleton {
    background: var(--bg-card);
    border: 1px solid var(--border-subtle);
    border-radius: 12px;
    animation: skeleton-pulse 1.8s ease-in-out infinite;
  }

  @keyframes skeleton-pulse {
    0%, 100% { opacity: 0.4; }
    50%       { opacity: 0.8; }
  }

  .hl-card-top {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 0.25rem;
  }

  .hl-icon {
    font-size: 1.1rem;
    color: var(--petronas-teal);
    opacity: 0.8;
  }

  .hl-label {
    font-size: 0.68rem;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--text-muted);
  }

  .hl-value {
    font-size: 2.2rem;
    font-weight: 700;
    color: var(--petronas-teal);
    line-height: 1;
    letter-spacing: -0.01em;
  }

  .hl-sub {
    font-size: 0.72rem;
    color: var(--text-secondary);
    margin-bottom: 0.4rem;
  }

  .hl-bar-track {
    height: 3px;
    background: var(--bg-surface);
    border-radius: 2px;
    overflow: hidden;
    margin-top: auto;
  }

  .hl-bar-fill {
    height: 100%;
    border-radius: 2px;
    transition: width 0.9s cubic-bezier(0.4, 0, 0.2, 1);
  }

  /* Sparklines */
  .hl-detail-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 2rem;
    padding: 1.25rem;
  }

  .hl-spark-block { 
    display: flex; 
    flex-direction: column; 
    gap: 0.5rem; 
  }

  .hl-spark-label {
    font-size: 0.68rem;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--text-muted);
  }

  .spark-bars {
    width: 100%;
    height: 48px;
  }

  @media (max-width: 900px) {
    .hl-grid            { grid-template-columns: 1fr 1fr; }
    .hl-detail-grid     { grid-template-columns: 1fr; }
  }
  @media (max-width: 480px) {
    .hl-grid            { grid-template-columns: 1fr; }
  }
</style>