<script lang="ts">
  import { untrack } from "svelte";
  import { snap } from "../stores/snapshot.svelte";
  import {
    formatHashrate,
    formatUptime,
    formatDifficulty,
    formatWork,
    expectedBlockSeconds,
    formatDuration,
  } from "../format";

  const data = $derived(snap.data!);
  const height = $derived(data.chain?.blocks ?? 0);

  const poolShare = $derived.by(() => {
    const net = data.network_hashrate_hs;
    if (!net || net <= 0) return 0;
    return data.hashrate_hs_1m / net;
  });

  const expected = $derived.by(() => {
    const diff = data.chain?.difficulty ?? 0;
    return expectedBlockSeconds(data.hashrate_hs_1m, data.network_hashrate_hs, diff);
  });

  // Round effort: share of the expected work-to-find-a-block that the
  // pool has already submitted, at the current network difficulty.
  // Matches ckpool's own accounted_diff_shares / network_diff * 100
  // (stratifier.c:8201).
  const roundEffort = $derived.by(() => {
    const d = data.chain?.difficulty ?? 0;
    if (!d || d <= 0) return 0;
    return (data.cumulative_shares / d) * 100;
  });

  // Blocks remaining + ETA until the retarget. The predicted adjustment
  // percent comes from the backend (computed from the epoch start time).
  const retarget = $derived.by(() => {
    if (!height) return { remaining: 2016, eta: "", progress: 0 };
    const inEpoch = height % 2016;
    const remaining = 2016 - inEpoch;
    const etaSec = remaining * 600;
    const progress = (inEpoch / 2016) * 100;
    return { remaining, eta: formatDuration(etaSec), progress };
  });

  const diffPct = $derived(data.next_difficulty_percent ?? 0);
  const diffPctLabel = $derived(
    diffPct === 0
      ? "—"
      : (diffPct > 0 ? "+" : "") + diffPct.toFixed(2) + "%",
  );

  const totalHashes = $derived(data.cumulative_shares * 2 ** 32);

  // Block update latency (ZMQ → mining.notify)
  const latencyAvg = $derived(data.latency_avg_ms ?? 0);
  const latencyLast = $derived(data.latency_last_ms ?? 0);
  const latencyCount = $derived(data.latency_count ?? 0);
  const staleWork = $derived(data.stale_work_hashes ?? 0);

  // Luck: best_share / cumulative_work * 100%.
  // 100% = exactly expected, >100% = lucky, <100% = unlucky.
  const luckPct = $derived.by(() => {
    const best = data.best_diff;
    const work = data.cumulative_shares;
    if (!best || !work || work <= 0) return 0;
    return (best / work) * 100;
  });
  const luckLabel = $derived.by(() => {
    if (!data.best_diff || !data.cumulative_shares) return "—";
    if (luckPct >= 1000) return `${(luckPct / 100).toFixed(1)}x`;
    return luckPct.toFixed(0) + "%";
  });

  // Block-height flash on network-wide new block.
  let prevHeight = $state(0);
  let heightFlash = $state(false);
  $effect(() => {
    const h = height;
    const prev = untrack(() => prevHeight);
    if (h > 0 && prev > 0 && h !== prev) {
      heightFlash = true;
      setTimeout(() => { heightFlash = false; }, 1800);
    }
    prevHeight = h;
  });
</script>

<section class="grid-5">
  <!-- Row 1 -->
  <div class="card">
    <div class="stat-label">Hashrate</div>
    <div class="stat-value">{formatHashrate(data.hashrate_hs_1m)}</div>
    <div class="stat-sub">
      5m {formatHashrate(data.hashrate_hs_5m)} · 1h {formatHashrate(data.hashrate_hs_1h)}
      · 24h {formatHashrate(data.hashrate_hs_24h)}
    </div>
  </div>

  <div class="card">
    <div class="stat-label">Best share</div>
    <div class="stat-value">{formatDifficulty(data.best_diff)}</div>
    <div
      class="luck-sub"
      class:lucky={luckPct > 100}
      class:unlucky={luckPct > 0 && luckPct < 100}
      title="Luck = best share / total work. 100% means your best share matches the work done. Above 100% is lucky (found a harder share than expected), below is unlucky."
    >
      <span class="luck-value">{luckLabel}</span>
      <span class="luck-label">luck</span>
    </div>
  </div>

  <div
    class="card"
    title="Time from receiving a new block via ZMQ to pushing mining.notify to all miners. Wasted work = hashes spent mining the old block during this window."
  >
    <div class="stat-label">Block latency</div>
    {#if latencyCount > 0}
      <div class="stat-value">{latencyAvg}<span class="unit">ms</span></div>
      <div class="stat-sub">
        last {latencyLast}ms ·
        <span class="wasted">{formatWork(staleWork)} wasted</span>
        <span class="stat-dim">({latencyCount} blocks)</span>
      </div>
    {:else}
      <div class="stat-value">—</div>
      <div class="stat-sub">waiting for the next block</div>
    {/if}
  </div>

  <div class="card">
    <div class="stat-label">Network</div>
    <div class="stat-value">{formatHashrate(data.network_hashrate_hs)}</div>
    <div class="stat-sub">pool share {(poolShare * 1e9).toFixed(2)} ppb</div>
  </div>

  <div class="card">
    <div class="stat-label">Difficulty</div>
    <div class="stat-value">{formatDifficulty(data.chain?.difficulty ?? 0)}</div>
    <div class="stat-sub">network target</div>
  </div>

  <!-- Row 2 -->
  <div class="card height-card" class:new-block={heightFlash}>
    <div class="stat-label">Block height</div>
    <div class="stat-value">{height ? height.toLocaleString() : "—"}</div>
    <div class="stat-sub">{data.chain?.chain ?? "—"}</div>
  </div>

  <div class="card">
    <div class="stat-label">Block reward</div>
    <div class="stat-value">
      {data.next_block_reward_btc ? data.next_block_reward_btc.toFixed(4) : "—"}
      <span class="unit">BTC</span>
    </div>
    <div class="stat-sub">subsidy + fees (next block)</div>
  </div>

  <div class="card">
    <div class="stat-label">Total work</div>
    <div class="stat-value">{formatWork(totalHashes)}</div>
    <div class="stat-sub">
      round effort {roundEffort.toFixed(1)}% of current difficulty
    </div>
  </div>

  <div class="card">
    <div class="stat-label">Expected block</div>
    <div class="stat-value">{formatDuration(expected)}</div>
    <div class="stat-sub">uptime {formatUptime(data.uptime_seconds)}</div>
  </div>

  <div class="card">
    <div class="stat-label">Next adjustment</div>
    <div
      class="stat-value adj"
      class:up={diffPct > 0}
      class:down={diffPct < 0}
    >{diffPctLabel}</div>
    <div class="stat-sub">
      <div class="retarget-bar">
        <div class="retarget-fill" style="width:{retarget.progress}%"></div>
      </div>
      <span>{retarget.remaining} blocks · ~{retarget.eta}</span>
    </div>
  </div>

</section>

<style>
  .grid-5 {
    display: grid;
    grid-template-columns: repeat(5, minmax(0, 1fr));
    gap: 1rem;
  }
  @media (max-width: 1100px) {
    .grid-5 {
      grid-template-columns: repeat(3, minmax(0, 1fr));
    }
  }
  @media (max-width: 720px) {
    .grid-5 {
      grid-template-columns: repeat(2, minmax(0, 1fr));
    }
  }

  .retarget-bar {
    height: 4px;
    background: var(--border);
    border-radius: 2px;
    overflow: hidden;
    margin: 0.4em 0 0.4em;
  }
  .retarget-fill {
    height: 100%;
    background: var(--accent);
    border-radius: 2px;
    transition: width 0.5s ease;
  }
  .unit {
    font-size: 0.65em;
    color: var(--fg-dim);
    font-weight: 400;
    margin-left: 0.15em;
  }
  .stat-dim {
    color: var(--fg-dim);
    font-size: 0.9em;
  }
  .wasted {
    color: var(--bad);
  }
  .adj.up {
    color: var(--good);
  }
  .adj.down {
    color: var(--bad);
  }

  .luck-sub {
    display: flex;
    align-items: baseline;
    gap: 0.4em;
    margin-top: 0.45em;
    cursor: help;
  }
  .luck-value {
    font-size: 1.15rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    letter-spacing: -0.01em;
  }
  .luck-label {
    color: var(--fg-dim);
    font-size: 0.85rem;
    font-weight: 400;
    text-transform: uppercase;
    letter-spacing: 0.04em;
  }
  .luck-sub.lucky .luck-value {
    color: var(--good);
    text-shadow: 0 0 10px rgba(92, 224, 168, 0.35);
  }
  .luck-sub.unlucky .luck-value {
    color: var(--bad);
    text-shadow: 0 0 10px rgba(255, 107, 107, 0.25);
  }

  .height-card {
    transition: box-shadow 0.3s, border-color 0.3s;
  }
  .height-card.new-block {
    animation: height-flash 1.8s ease-out;
  }
  @keyframes height-flash {
    0% {
      border-color: var(--accent);
      box-shadow: 0 0 0 2px var(--accent), 0 0 32px rgba(255, 122, 58, 0.55);
      transform: scale(1.03);
    }
    40% {
      border-color: var(--accent);
      box-shadow: 0 0 0 1px var(--accent), 0 0 20px rgba(255, 122, 58, 0.35);
      transform: scale(1);
    }
    100% {
      border-color: var(--border);
      box-shadow: none;
      transform: scale(1);
    }
  }
</style>
