import { useEffect, useRef, useState } from 'react';
import type { Message } from '@/api/types';
import { cn } from '@/lib/utils';

interface Props {
  messages: Message[];
  // Zero-state fallback: the model's full context window from
  // chat.model_context_limit (server getModelContext lookup). Lets the ring
  // render a meaningful 0% before any assistant turn has reported usage.
  modelContextLimit?: number | null;
  // Optional session cost (USD). Omitted today (local llama-swap is free); the
  // popover line only shows when a positive number is passed.
  sessionCostUsd?: number | null;
}

const SIZE = 18;
const CENTER = SIZE / 2;
const RADIUS = 7;
const STROKE = 2.25;
const CIRCUMFERENCE = 2 * Math.PI * RADIUS;

// Take the latest ctx_used and ctx_max INDEPENDENTLY (newest-first) — they need
// not be on the same message (some agents report the window only intermittently
// while reporting usage every turn). Mirrors the old ContextBar logic.
function latestPair(messages: Message[]): { used: number; max: number } | null {
  let used: number | null = null;
  let max: number | null = null;
  for (let i = messages.length - 1; i >= 0; i--) {
    const m = messages[i]!;
    if (used === null && m.ctx_used != null) used = m.ctx_used;
    if (max === null && m.ctx_max != null && m.ctx_max > 0) max = m.ctx_max;
    if (used !== null && max !== null) break;
  }
  return used !== null && max !== null ? { used, max } : null;
}

function formatTokens(v: number): string {
  if (v >= 1_000_000) return `${Math.round(v / 1_000_000)}m`;
  if (v >= 1_000) return `${Math.round(v / 1_000)}k`;
  return `${Math.round(v)}`;
}

function formatCost(v: number): string {
  return v < 0.01 ? `$${v.toFixed(4)}` : `$${v.toFixed(2)}`;
}

export function ContextMeter({ messages, modelContextLimit, sessionCostUsd }: Props) {
  const [open, setOpen] = useState(false);
  const ref = useRef<HTMLDivElement>(null);

  useEffect(() => {
    if (!open) return;
    const onDown = (e: MouseEvent | TouchEvent) => {
      if (ref.current && !ref.current.contains(e.target as Node)) setOpen(false);
    };
    document.addEventListener('mousedown', onDown);
    document.addEventListener('touchstart', onDown);
    return () => {
      document.removeEventListener('mousedown', onDown);
      document.removeEventListener('touchstart', onDown);
    };
  }, [open]);

  const pair = latestPair(messages);
  const max = pair?.max ?? (modelContextLimit && modelContextLimit > 0 ? modelContextLimit : null);
  const used = pair?.used ?? 0;

  const ratio = max ? Math.max(0, Math.min(1, used / max)) : 0;
  const rounded = max ? Math.round((used / max) * 100) : null;
  const offset = CIRCUMFERENCE - ratio * CIRCUMFERENCE;

  // Paseo thresholds on raw usage: muted < 70%, amber 70–90%, red > 90%.
  const progressClass =
    rounded === null
      ? 'stroke-muted-foreground/40'
      : rounded > 90
        ? 'stroke-red-500'
        : rounded >= 70
          ? 'stroke-amber-500'
          : 'stroke-muted-foreground';
  const labelClass =
    rounded === null
      ? 'text-muted-foreground'
      : rounded > 90
        ? 'text-red-600 dark:text-red-400'
        : rounded >= 70
          ? 'text-amber-600 dark:text-amber-400'
          : 'text-muted-foreground';

  const cost =
    typeof sessionCostUsd === 'number' && sessionCostUsd > 0 ? formatCost(sessionCostUsd) : null;

  return (
    <div ref={ref} className="relative shrink-0">
      <button
        type="button"
        onClick={() => setOpen((v) => !v)}
        aria-label={`Context window ${rounded ?? 0}% used`}
        title={rounded === null ? 'Model context unknown' : `Context window ${rounded}% used`}
        className="inline-flex items-center gap-1 rounded-full px-1 text-muted-foreground hover:text-foreground max-md:min-h-[36px]"
      >
        <svg width={SIZE} height={SIZE} viewBox={`0 0 ${SIZE} ${SIZE}`} className="-rotate-90 shrink-0">
          <circle
            cx={CENTER}
            cy={CENTER}
            r={RADIUS}
            fill="none"
            className="stroke-muted"
            strokeWidth={STROKE}
          />
          <circle
            cx={CENTER}
            cy={CENTER}
            r={RADIUS}
            fill="none"
            className={cn('transition-all duration-200 motion-reduce:transition-none', progressClass)}
            strokeWidth={STROKE}
            strokeLinecap="round"
            strokeDasharray={CIRCUMFERENCE}
            strokeDashoffset={offset}
          />
        </svg>
        <span className={cn('text-[11px] font-mono tabular-nums', labelClass)}>
          {rounded === null ? '—' : `${rounded}%`}
        </span>
      </button>
      {open && (
        <div className="absolute bottom-full right-0 z-50 mb-2 w-max rounded-lg border border-border bg-popover px-3 py-2 text-left shadow-md">
          <p className="text-sm text-foreground">Context window</p>
          <p className="text-sm text-foreground">{rounded === null ? 'Unknown' : `${rounded}% used`}</p>
          {max !== null && (
            <p className="text-xs text-muted-foreground">
              {formatTokens(used)} / {formatTokens(max)} tokens
            </p>
          )}
          {cost && <p className="text-xs text-muted-foreground">Session cost {cost}</p>}
        </div>
      )}
    </div>
  );
}
