import { ConnectionQuality, type Room } from 'livekit-client';
import { useEffect, useRef, useState } from 'react';

import {
  type ParticipantStats,
  makeSampleCache,
  sampleStats,
} from '../lib/callStats';
import { useCall } from '../context/CallContext';
import { XIcon } from './icons';

interface Props {
  room: Room;
  members: { userId: string; profile?: { displayName?: string | null } | null }[];
  onClose: () => void;
}

const POLL_INTERVAL_MS = 1500;

const QUALITY_LABEL: Record<ConnectionQuality, string> = {
  [ConnectionQuality.Excellent]: 'Sehr gut',
  [ConnectionQuality.Good]: 'Gut',
  [ConnectionQuality.Poor]: 'Schlecht',
  [ConnectionQuality.Lost]: 'Verloren',
  [ConnectionQuality.Unknown]: 'Unbekannt',
};

const QUALITY_TONE: Record<ConnectionQuality, string> = {
  [ConnectionQuality.Excellent]: 'text-emerald-400',
  [ConnectionQuality.Good]: 'text-emerald-400',
  [ConnectionQuality.Poor]: 'text-amber-400',
  [ConnectionQuality.Lost]: 'text-rose-400',
  [ConnectionQuality.Unknown]: 'text-fg-muted',
};

/**
 * Discord-style debug overlay (Ctrl+Shift+S). Polls WebRTC getStats() every
 * 1.5s and renders bitrate/loss/jitter/RTT per participant + audio + video.
 * Pin to corner; designed to stay readable on top of any video stream.
 */
export function CallStatsOverlay({ room, members, onClose }: Props) {
  const { connectionQualities } = useCall();
  const [stats, setStats] = useState<ParticipantStats[]>([]);
  const cacheRef = useRef(makeSampleCache());

  useEffect(() => {
    let cancelled = false;
    const tick = async () => {
      try {
        const next = await sampleStats(room, cacheRef.current);
        if (!cancelled) setStats(next);
      } catch {
        /* ignore — getStats can throw mid-reconnect */
      }
    };
    void tick();
    const id = window.setInterval(() => {
      void tick();
    }, POLL_INTERVAL_MS);
    return () => {
      cancelled = true;
      window.clearInterval(id);
    };
  }, [room]);

  const nameFor = (identity: string): string => {
    const m = members.find((mm) => mm.userId === identity);
    return m?.profile?.displayName ?? identity.slice(0, 8);
  };

  return (
    <div
      role="dialog"
      aria-label="Call-Statistiken"
      className="fixed right-4 top-4 z-[110] w-[320px] overflow-hidden rounded-xl border border-line bg-black/85 text-[11px] text-white shadow-2xl backdrop-blur-md"
    >
      <header className="flex items-center justify-between border-b border-white/10 px-3 py-2">
        <div>
          <div className="text-[10px] font-semibold uppercase tracking-[0.12em] text-white/60">
            Debug
          </div>
          <div className="font-display text-sm font-bold">Call-Stats</div>
        </div>
        <button
          type="button"
          onClick={onClose}
          aria-label="Stats schließen"
          className="cursor-pointer rounded-md p-1 text-white/70 transition hover:bg-white/10 hover:text-white"
        >
          <XIcon className="h-4 w-4" />
        </button>
      </header>
      <div className="max-h-[60vh] overflow-y-auto px-3 py-2 space-y-2 font-mono">
        {stats.map((p) => {
          const cq = connectionQualities[p.identity] ?? ConnectionQuality.Unknown;
          return (
            <div
              key={p.identity}
              className="rounded-md border border-white/10 bg-white/5 p-2"
            >
              <div className="mb-1 flex items-center justify-between gap-2">
                <span className="truncate font-semibold">
                  {nameFor(p.identity)}
                  {p.isLocal && <span className="ml-1 text-white/50">(du)</span>}
                </span>
                <span className={'text-[10px] tabular-nums ' + QUALITY_TONE[cq]}>
                  {QUALITY_LABEL[cq]}
                </span>
              </div>
              {p.isLocal ? (
                <Row
                  label="Audio out"
                  values={[fmtKbps(p.audio.audioOutKbps)]}
                />
              ) : (
                <Row
                  label="Audio in"
                  values={[
                    fmtKbps(p.audio.audioInKbps),
                    fmtPct(p.audio.packetLossPct, 'loss'),
                    fmtMs(p.audio.jitterMs, 'jit'),
                    fmtMs(p.audio.rttMs, 'rtt'),
                  ]}
                />
              )}
              {(p.video.videoInKbps ?? p.video.videoOutKbps ?? 0) > 0 && (
                p.isLocal ? (
                  <Row
                    label="Video out"
                    values={[fmtKbps(p.video.videoOutKbps)]}
                  />
                ) : (
                  <Row
                    label="Video in"
                    values={[
                      fmtKbps(p.video.videoInKbps),
                      fmtPct(p.video.packetLossPct, 'loss'),
                      fmtMs(p.video.jitterMs, 'jit'),
                      fmtMs(p.video.rttMs, 'rtt'),
                    ]}
                  />
                )
              )}
            </div>
          );
        })}
        {stats.length === 0 && (
          <p className="px-1 py-1.5 text-white/60">Sammle Stats …</p>
        )}
      </div>
      <footer className="border-t border-white/10 px-3 py-1.5 text-[10px] text-white/50">
        Aktualisiert alle 1,5 s · Strg+Shift+S zum Schließen
      </footer>
    </div>
  );
}

function Row({ label, values }: { label: string; values: (string | null)[] }) {
  const visible = values.filter(Boolean) as string[];
  return (
    <div className="flex items-baseline gap-1.5">
      <span className="w-[58px] shrink-0 text-white/50">{label}</span>
      <span className="flex flex-wrap gap-x-2 tabular-nums text-white/90">
        {visible.length === 0 ? '—' : visible.map((v, i) => <span key={i}>{v}</span>)}
      </span>
    </div>
  );
}

function fmtKbps(v: number | undefined): string | null {
  if (v === undefined) return null;
  return v.toLocaleString('de') + ' kbps';
}

function fmtPct(v: number | undefined, prefix: string): string | null {
  if (v === undefined) return null;
  return prefix + ' ' + v.toFixed(1) + '%';
}

function fmtMs(v: number | undefined, prefix: string): string | null {
  if (v === undefined) return null;
  return prefix + ' ' + v + 'ms';
}
