/**
 * ProxyStatsWidget — live RAM-usage + hit-rate panel for the Stream
 * Proxy (Restreaming) feature.
 *
 * Polls /api/proxy/stats every 5 s. Works against BOTH the Python
 * FastAPI backend (in-process RAM, backend === "ram") and the PHP
 * cPanel backend (apcu / redis / file). Same JSON wire format on
 * either side.
 *
 * Renders:
 *   • Backend badge with colour-coded warning when "file" (slow)
 *   • Buffer used vs cap (200 MB) — animated bar
 *   • Cache hit / miss / hit-rate
 *   • Active upstream streams (single-fetch effectiveness signal)
 */
import { useEffect, useState } from "react";
import { Activity, Database, Loader2, Server, Zap } from "lucide-react";

import { getToken } from "@/lib/nadiAuth";

/** Tiny GET helper that adds the bearer token from localStorage. */
const authedFetch = (url: string): Promise<Response> => {
  const token = getToken();
  const headers: Record<string, string> = { Accept: "application/json" };
  if (token) headers.Authorization = `Bearer ${token}`;
  return fetch(url, { method: "GET", headers });
};

interface UpstreamError {
  where: string;
  url: string;
  http?: number;
  errno?: number;
  msg: string;
  ts: string;
}

interface Stats {
  backend: "apcu" | "redis" | "file" | "ram" | string;
  cached_segments: number;
  buffer_bytes: number;
  buffer_max_bytes: number;
  buffer_pct: number;
  ttl_seconds: number;
  hits: number;
  misses: number;
  hit_rate_pct: number;
  active_streams: number;
  /** How many times any device has hit POST /api/proxy/sign.
   *  If this stays at 0 while subscribers are watching live TV, the
   *  installed APK was built before the proxy substitution code →
   *  rebuild + reinstall. */
  sign_requests?: number;
  /** Most-recent failure when the proxy tried to fetch from upstream.
   *  When non-null, the admin can read the exact reason (cURL errno,
   *  HTTP status, message) in plain English instead of grepping logs. */
  last_upstream_error?: UpstreamError | null;
}

const fmtBytes = (b: number): string => {
  if (b <= 0) return "0 B";
  const u = ["B", "KB", "MB", "GB"];
  let i = 0;
  let v = b;
  while (v >= 1024 && i < u.length - 1) {
    v /= 1024;
    i += 1;
  }
  return `${v.toFixed(v >= 10 || i === 0 ? 0 : 1)} ${u[i]}`;
};

const backendLabel = (b: string): { name: string; tone: string; hint: string } => {
  switch (b) {
    case "apcu":
      return { name: "APCu", tone: "ok",
        hint: "In-memory shared across PHP-FPM workers — fastest cPanel option." };
    case "redis":
      return { name: "Redis", tone: "ok",
        hint: "External cache, network-fast, scales horizontally." };
    case "ram":
      return { name: "Python RAM", tone: "ok",
        hint: "FastAPI in-process hub — sub-millisecond hits." };
    case "file":
      return { name: "File", tone: "warn",
        hint: "Filesystem fallback — works everywhere but slowest." };
    default:
      return { name: b || "—", tone: "neutral", hint: "Unknown backend." };
  }
};

const ProxyStatsWidget = ({
  apiBase,
  pollMs = 5000,
}: {
  apiBase: string;
  pollMs?: number;
}) => {
  const [stats, setStats] = useState<Stats | null>(null);
  const [error, setError] = useState<string | null>(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    let cancelled = false;
    let timer: number | null = null;
    const poll = async () => {
      try {
        const r = await authedFetch(`${apiBase}/api/proxy/stats`);
        if (!r.ok) throw new Error(`HTTP ${r.status}`);
        const j = (await r.json()) as Stats;
        if (cancelled) return;
        setStats(j);
        setError(null);
      } catch (e: any) {
        if (cancelled) return;
        setError(e?.message || "fetch failed");
      } finally {
        if (cancelled) return;
        setLoading(false);
        timer = window.setTimeout(poll, pollMs);
      }
    };
    poll();
    return () => {
      cancelled = true;
      if (timer !== null) window.clearTimeout(timer);
    };
  }, [apiBase, pollMs]);

  const b = stats ? backendLabel(stats.backend) : null;
  const toneClass =
    b?.tone === "ok"
      ? "bg-emerald-500/15 text-emerald-300 border-emerald-500/40"
      : b?.tone === "warn"
        ? "bg-amber-500/15 text-amber-300 border-amber-500/40"
        : "bg-muted/30 text-muted-foreground border-border";

  return (
    <div
      data-testid="proxy-stats-widget"
      className="glass-card rounded-xl border border-primary/15 p-4 sm:p-5 space-y-4"
    >
      <header className="flex items-center justify-between">
        <div className="flex items-center gap-2">
          <Server className="w-4 h-4 text-primary/80" />
          <h3 className="font-display text-sm tracking-[0.2em] uppercase text-primary/90">
            Stream Proxy
          </h3>
        </div>
        {loading && !stats ? (
          <Loader2 className="w-4 h-4 animate-spin text-muted-foreground" />
        ) : error ? (
          <span className="text-[10px] text-rose-400" data-testid="proxy-stats-error">
            {error}
          </span>
        ) : null}
      </header>

      {stats ? (
        <>
          {/* Backend badge */}
          <div className="flex flex-wrap items-center gap-2">
            <span
              data-testid="proxy-stats-backend"
              className={`text-[10px] tracking-[0.18em] uppercase px-2 py-1 rounded border ${toneClass}`}
            >
              {b?.name}
            </span>
            <span className="text-[11px] text-muted-foreground">{b?.hint}</span>
          </div>

          {/* Buffer usage bar */}
          <div className="space-y-1.5">
            <div className="flex items-center justify-between text-[11px]">
              <span className="text-muted-foreground flex items-center gap-1.5">
                <Database className="w-3 h-3" />
                Buffer
              </span>
              <span className="text-foreground font-mono" data-testid="proxy-stats-buffer">
                {fmtBytes(stats.buffer_bytes)} / {fmtBytes(stats.buffer_max_bytes)} ({stats.buffer_pct}%)
              </span>
            </div>
            <div className="h-2 rounded-full bg-muted/30 overflow-hidden">
              <div
                className="h-full bg-gradient-to-r from-primary/70 to-primary transition-all duration-700"
                style={{ width: `${Math.min(100, stats.buffer_pct)}%` }}
              />
            </div>
          </div>

          {/* KPI grid */}
          <div className="grid grid-cols-2 sm:grid-cols-4 gap-2">
            <Kpi
              testId="proxy-stats-sign-requests"
              label="Sign requests"
              value={String(stats.sign_requests ?? 0)}
              sub={
                (stats.sign_requests ?? 0) > 0
                  ? "device(s) talking to proxy ✓"
                  : "no device hit /sign yet — APK may be stale"
              }
              icon={<Server className="w-3.5 h-3.5" />}
              tone={(stats.sign_requests ?? 0) > 0 ? "ok" : "warn"}
            />
            <Kpi
              testId="proxy-stats-cached"
              label="Cached segments"
              value={String(stats.cached_segments)}
              icon={<Database className="w-3.5 h-3.5" />}
            />
            <Kpi
              testId="proxy-stats-hit-rate"
              label="Hit rate"
              value={`${stats.hit_rate_pct}%`}
              sub={`${stats.hits} hits · ${stats.misses} misses`}
              icon={<Zap className="w-3.5 h-3.5" />}
              tone={
                stats.hit_rate_pct >= 75
                  ? "ok"
                  : stats.hit_rate_pct >= 40
                    ? "warn"
                    : "neutral"
              }
            />
            <Kpi
              testId="proxy-stats-active"
              label="Active upstreams"
              value={String(stats.active_streams)}
              sub="(in-flight)"
              icon={<Activity className="w-3.5 h-3.5" />}
              tone={stats.active_streams > 30 ? "warn" : "neutral"}
            />
          </div>

          {/* Last upstream error — only renders when the proxy
              actually failed to reach upstream. Surfaces the curl
              errno + HTTP status + message so the admin doesn't
              have to SSH in to diagnose. */}
          {stats.last_upstream_error ? (
            <div
              data-testid="proxy-last-upstream-error"
              className="mt-3 rounded-lg border border-rose-500/40 bg-rose-500/5 px-3 py-2 text-[11px] leading-relaxed text-rose-200"
            >
              <div className="font-semibold uppercase tracking-[0.18em] text-[9px] mb-1 text-rose-300">
                Last upstream error
              </div>
              <div>
                <span className="opacity-60">when:</span>{" "}
                {stats.last_upstream_error.ts} ·{" "}
                <span className="opacity-60">where:</span>{" "}
                {stats.last_upstream_error.where}
                {typeof stats.last_upstream_error.http === "number"
                  ? ` · http=${stats.last_upstream_error.http}`
                  : ""}
                {typeof stats.last_upstream_error.errno === "number"
                  ? ` · curl=${stats.last_upstream_error.errno}`
                  : ""}
              </div>
              <div className="mt-1 break-all">
                <span className="opacity-60">url:</span>{" "}
                {stats.last_upstream_error.url}
              </div>
              <div className="mt-1 break-words">
                <span className="opacity-60">msg:</span>{" "}
                {stats.last_upstream_error.msg}
              </div>
            </div>
          ) : null}
        </>
      ) : !error ? (
        <p className="text-[11px] text-muted-foreground">Loading…</p>
      ) : (
        <p className="text-[11px] text-rose-400">
          Could not reach /api/proxy/stats — make sure you're logged in as admin.
        </p>
      )}
    </div>
  );
};

const Kpi = ({
  label,
  value,
  sub,
  icon,
  tone = "neutral",
  testId,
}: {
  label: string;
  value: string;
  sub?: string;
  icon?: React.ReactNode;
  tone?: "ok" | "warn" | "neutral";
  testId?: string;
}) => (
  <div
    data-testid={testId}
    className="rounded-lg border border-border/40 bg-background/40 px-3 py-2"
  >
    <div className="flex items-center gap-1.5 text-[9px] tracking-[0.15em] uppercase text-muted-foreground">
      {icon}
      <span className="truncate">{label}</span>
    </div>
    <div
      className={`text-base font-semibold mt-0.5 ${
        tone === "ok"
          ? "text-emerald-300"
          : tone === "warn"
            ? "text-amber-300"
            : "text-foreground"
      }`}
    >
      {value}
    </div>
    {sub ? (
      <div className="text-[10px] text-muted-foreground/80 leading-tight">{sub}</div>
    ) : null}
  </div>
);

export default ProxyStatsWidget;
