import { Info } from "lucide-react";
import { type JSX, useMemo } from "react";
import { cn, formatTokens } from "../../../lib/utils";
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "../../ui/tooltip";
import { SegmentBar } from "./SegmentBar";
import type { AnatomySegment } from "./types";

export type RequestAnatomyProps = {
  /** Parsed request body, or `null` if it cannot be parsed. */
  parsed: unknown | null;
  /** Server-reported input token count, or `null` if unknown. */
  inputTokens: number | null;
  /** Optional callback fired when the user activates a segment. */
  onSegmentActivate?: (segment: AnatomySegment) => void;
  /** Pre-computed segments; if provided, `parsed` is ignored. */
  segments?: AnatomySegment[] | null;
};

const DIVERGENCE_AMBER_THRESHOLD = 0.25;

/**
 * Render the request anatomy view: a one-line summary plus the
 * stacked segment bar. Returns `null` when the request cannot be
 * parsed or the segment list is empty.
 */
export function RequestAnatomy({
  parsed,
  inputTokens,
  onSegmentActivate,
  segments: providedSegments,
}: RequestAnatomyProps): JSX.Element | null {
  // Caller is expected to pre-compute segments in production (see
  // LogEntry). When called standalone, fall back to deriving from
  // `parsed` directly using the unknown adapter is not appropriate —
  // the caller is responsible for choosing the right adapter.
  const segments = useMemo(() => providedSegments ?? null, [providedSegments]);
  const total = useMemo(() => (segments ?? []).reduce((sum, s) => sum + s.size, 0), [segments]);

  // Show divergence warning when both estimate and server numbers exist.
  const showDivergenceWarning = useMemo(() => {
    if (segments === null || segments === undefined) return false;
    if (inputTokens === null) return false;
    if (total === 0) return false;
    const ratio = Math.abs(inputTokens - total) / Math.max(inputTokens, total);
    return ratio >= DIVERGENCE_AMBER_THRESHOLD;
  }, [inputTokens, segments, total]);

  const summaryColorClass = useMemo(() => {
    if (inputTokens === null) return "text-muted-foreground";
    if (showDivergenceWarning) return "text-amber-400";
    return "text-muted-foreground";
  }, [inputTokens, showDivergenceWarning]);

  if (segments === null || segments === undefined) {
    return null;
  }
  if (segments.length === 0) {
    return null;
  }
  if (parsed === null && providedSegments === undefined) {
    return null;
  }

  return (
    <TooltipProvider delayDuration={150}>
      <div className="px-4 py-3 space-y-2" data-testid="anatomy-root">
        <div className="flex items-center gap-2 text-xs">
          <span className="font-mono tabular-nums text-foreground">
            ~{formatTokens(total)} tokens
          </span>
          {inputTokens !== null && (
            <span className={cn("font-mono tabular-nums", summaryColorClass)}>
              (server: {formatTokens(inputTokens)})
            </span>
          )}
          {showDivergenceWarning && (
            <Tooltip>
              <TooltipTrigger asChild>
                <button
                  type="button"
                  className="inline-flex items-center text-amber-400 hover:text-amber-300"
                  aria-label="Token estimate diverges from server"
                >
                  <Info className="size-3.5" />
                </button>
              </TooltipTrigger>
              <TooltipContent className="max-w-xs text-xs">
                Bar uses a token estimate heuristic (~4 ASCII chars / token, ~1 CJK / emoji char per
                token). The server&apos;s reported value is the source of truth for cost.
              </TooltipContent>
            </Tooltip>
          )}
        </div>
        <SegmentBar segments={segments} totalTokens={total} onActivate={onSegmentActivate} />
      </div>
    </TooltipProvider>
  );
}
