import { type JSX, memo, useCallback, useEffect, useMemo, useRef, useState } from "react";
import { AlertTriangle, ChevronRight, Clock, Zap } from "lucide-react";
import { isTurnBoundary } from "../../lib/stopReason";
import { cn, formatTokens } from "../../lib/utils";
import type { CapturedLog } from "../../proxy/schemas";
import { getCrabVariant } from "../ui/crab-variants";
import { ProviderLogo, detectProvider, type Provider } from "../providers/ProviderLogo";
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "../ui/tooltip";
import type { CacheTrendEntry } from "./cacheTrend";
import { LogEntry } from "./LogEntry";
import { ThreadConnector } from "./ThreadConnector";
import { isTurnCollapsible, type TurnEntry } from "./viewerState";

function formatElapsed(ms: number): string {
  if (ms < 1000) return `${ms}ms`;
  return `${(ms / 1000).toFixed(1)}s`;
}

type TurnGroupProps = {
  entries: TurnEntry[];
  viewMode: "simple" | "full";
  strip: boolean;
  slowResponseThresholdSeconds: number;
  cacheTrends?: Map<number, CacheTrendEntry>;
  onCompareWithPrevious: (log: CapturedLog) => void;
  comparisonPredecessors: Map<number, CapturedLog>;
  turnIndex?: number;
};

export const TurnGroup = memo(function TurnGroup({
  entries,
  viewMode,
  strip,
  slowResponseThresholdSeconds,
  cacheTrends,
  onCompareWithPrevious,
  comparisonPredecessors,
  turnIndex = 0,
}: TurnGroupProps): JSX.Element {
  const lastIdx = entries.length - 1;
  const lastStop = entries[lastIdx]?.stopReason ?? null;
  const isComplete = lastStop !== null ? isTurnBoundary(lastStop) : false;
  const isPending = entries[lastIdx]?.log.responseStatus === null;
  const isSingleLog = entries.length === 1;
  const collapsible = isTurnCollapsible(entries.length, isComplete, isPending);
  const [collapsed, setCollapsed] = useState(false);

  // Auto-collapse when the turn finishes (transitions from incomplete → complete)
  const prevCompleteRef = useRef(false);
  useEffect(() => {
    if (!collapsible) {
      setCollapsed(false);
    } else if (isComplete && !prevCompleteRef.current) {
      setCollapsed(true);
    }
    prevCompleteRef.current = isComplete;
  }, [collapsible, isComplete]);

  const toggleCollapse = useCallback(() => {
    if (collapsible) setCollapsed((prev) => !prev);
  }, [collapsible]);

  // Aggregate totals for collapsed summary
  const aggregate = useMemo(() => {
    let totalInput = 0;
    let totalOutput = 0;
    let maxElapsed: number | null = null;
    let hasTokens = false;
    for (const e of entries) {
      if (e.log.inputTokens !== null) {
        totalInput += e.log.inputTokens;
        hasTokens = true;
      }
      if (e.log.outputTokens !== null) {
        totalOutput += e.log.outputTokens;
        hasTokens = true;
      }
      if (e.log.elapsedMs !== null) {
        maxElapsed = maxElapsed === null ? e.log.elapsedMs : Math.max(maxElapsed, e.log.elapsedMs);
      }
    }
    return {
      totalInput,
      totalOutput,
      hasTokens,
      maxElapsed,
    };
  }, [entries, lastIdx]);

  // Unique providers across all entries (for collapsed model logos)
  const uniqueProviders = useMemo(() => {
    const seen = new Set<Provider>();
    for (const e of entries) {
      const p = detectProvider(e.log.model);
      if (p !== "unknown") seen.add(p);
    }
    return [...seen];
  }, [entries]);

  // Crab variant creators for the dual-crab collapsed layout
  const StartCrab = useMemo(() => getCrabVariant(entries[0]?.log.id ?? 0), [entries]);
  const EndCrab = useMemo(() => getCrabVariant(entries[lastIdx]?.log.id ?? 0), [entries, lastIdx]);

  const bgClass = turnIndex % 2 === 0 ? "bg-muted/10" : "bg-muted/25";
  const aggregateIsSlow =
    aggregate.maxElapsed !== null &&
    slowResponseThresholdSeconds > 0 &&
    aggregate.maxElapsed > slowResponseThresholdSeconds * 1000;

  // ResizeObserver → re-render connectors when any LogEntry height changes
  const [layoutVersion, setLayoutVersion] = useState(0);
  const containerRef = useRef<HTMLDivElement>(null);
  useEffect(() => {
    const el = containerRef.current;
    if (!el) return;
    let raf = 0;
    const ro = new ResizeObserver(() => {
      window.cancelAnimationFrame(raf);
      raf = window.requestAnimationFrame(() => setLayoutVersion((v) => v + 1));
    });
    ro.observe(el);
    return () => {
      ro.disconnect();
      window.cancelAnimationFrame(raf);
    };
  }, []);

  return (
    <div
      ref={containerRef}
      className={cn("border rounded-lg", isPending ? "border-amber-500/10" : "border-transparent")}
    >
      {collapsed ? (
        /* ---- Collapsed: dual-crab (+ summary card for multi-log turns) ---- */
        <div
          data-nav-id={`turn-collapsed-${entries[0]?.log.id ?? turnIndex}`}
          data-nav-action="expand"
          role="button"
          tabIndex={0}
          className="flex items-stretch cursor-pointer focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:outline-none rounded-lg"
          onClick={toggleCollapse}
          onKeyDown={(e) => {
            if (e.key === "Enter" || e.key === " ") {
              e.preventDefault();
              toggleCollapse();
            }
          }}
        >
          {/* Turn number */}
          <div className="w-5 shrink-0 flex items-start pt-1.5">
            <span className="text-[10px] text-muted-foreground/50 font-mono tabular-nums leading-none select-none">
              {turnIndex + 1}
            </span>
          </div>

          {/* Dual-crab connector for collapsed multi-request turns. */}
          <div className="w-6 shrink-0 flex flex-col items-center pt-0.5 pb-0.5">
            <div className="flex justify-center h-[calc(0.75rem-8px)]" />
            <span
              role="button"
              tabIndex={0}
              title="Start of turn — click to expand"
              className="cursor-pointer"
              onClick={(e) => {
                e.stopPropagation();
                toggleCollapse();
              }}
              onKeyDown={(e) => {
                if (e.key === "Enter" || e.key === " ") {
                  e.preventDefault();
                  toggleCollapse();
                }
              }}
            >
              <StartCrab
                className={cn(
                  "size-3.5 text-emerald-400",
                  "animate-crab-appear drop-shadow-[0_0_4px_rgba(52,211,153,0.5)]",
                )}
              />
            </span>

            <div className="flex-1 flex justify-center min-h-0">
              <div className="w-0.5 bg-muted-foreground/30 h-full" />
            </div>

            <span
              role="button"
              tabIndex={0}
              title="End of Turn — click to expand"
              className="cursor-pointer"
              onClick={(e) => {
                e.stopPropagation();
                toggleCollapse();
              }}
              onKeyDown={(e) => {
                if (e.key === "Enter" || e.key === " ") {
                  e.preventDefault();
                  toggleCollapse();
                }
              }}
            >
              <EndCrab
                className={cn(
                  "size-3.5 text-amber-400",
                  "animate-crab-settle drop-shadow-[0_0_4px_rgba(251,191,36,0.5)]",
                )}
              />
            </span>
          </div>

          {/* Summary content — hidden for single-log turns. */}
          {entries.length > 1 && (
            <div
              className={cn(
                "flex-1 min-w-0 mb-0.5 rounded-lg border border-border py-1 px-3 flex items-center gap-3 text-xs",
                bgClass,
              )}
            >
              {/* ID range */}
              <span className="text-blue-400/80 font-mono font-semibold tabular-nums shrink-0">
                #{entries[0]?.log.id ?? "?"} ~ #{entries[lastIdx]?.log.id ?? "?"}
              </span>

              {/* Request count */}
              <span className="text-muted-foreground shrink-0">
                {entries.length} request{entries.length > 1 ? "s" : ""}
              </span>

              {/* Model logos — one per unique provider */}
              {uniqueProviders.length > 0 && (
                <span className="flex items-center gap-0.5 shrink-0">
                  {uniqueProviders.map((p) => (
                    <ProviderLogo key={p} provider={p} className="size-4" />
                  ))}
                </span>
              )}

              {/* Elapsed — slowest single request in the turn (not the sum) */}
              {aggregate.maxElapsed !== null && (
                <TooltipProvider>
                  <Tooltip>
                    <TooltipTrigger asChild>
                      <span
                        className={cn(
                          "flex items-center gap-1 shrink-0",
                          aggregateIsSlow ? "text-amber-400" : "text-muted-foreground",
                        )}
                      >
                        <Clock className="size-3" />
                        <span className="font-mono tabular-nums">
                          {formatElapsed(aggregate.maxElapsed)}
                        </span>
                        {aggregateIsSlow && (
                          <AlertTriangle className="size-3" aria-label="Slow response" />
                        )}
                      </span>
                    </TooltipTrigger>
                    <TooltipContent>
                      {aggregateIsSlow
                        ? `Slow response: ${formatElapsed(
                            aggregate.maxElapsed,
                          )} exceeds ${formatElapsed(slowResponseThresholdSeconds * 1000)}`
                        : "Slowest request in this turn"}
                    </TooltipContent>
                  </Tooltip>
                </TooltipProvider>
              )}

              {/* Tokens */}
              {aggregate.hasTokens && (
                <span className="flex items-center gap-1 shrink-0">
                  <Zap className="size-3 text-muted-foreground" />
                  <span className="font-mono tabular-nums">
                    <span className="text-blue-400">IN {formatTokens(aggregate.totalInput)}</span>
                    {" / "}
                    <span className="text-amber-400">
                      OUT {formatTokens(aggregate.totalOutput)}
                    </span>
                  </span>
                </span>
              )}

              {/* Spacer */}
              <span className="flex-1 min-w-0" />

              {/* Expand chevron */}
              <ChevronRight className="size-4 text-muted-foreground shrink-0" />
            </div>
          )}
        </div>
      ) : (
        /* ---- Expanded: full entries ---- */
        entries.map((entry, visibleIdx) => {
          const { log, stopReason: reason } = entry;
          const isTurnStart = visibleIdx === 0;

          return (
            <div key={log.id} className="flex items-stretch">
              {isTurnStart ? (
                <div className="w-5 shrink-0 flex items-start pt-1.5">
                  <span className="text-[10px] text-muted-foreground/50 font-mono tabular-nums leading-none select-none">
                    {turnIndex + 1}
                  </span>
                </div>
              ) : (
                <div className="w-5 shrink-0" />
              )}
              <ThreadConnector
                stopReason={reason}
                isPending={log.responseStatus === null}
                isFirst={visibleIdx === 0}
                isTurnStart={isTurnStart}
                isOnlyEntry={isSingleLog}
                crabIndex={log.id % 12}
                collapsible={collapsible && isTurnStart}
                onToggle={toggleCollapse}
              />
              <div className={cn("flex-1 min-w-0 mb-0.5 rounded-lg", bgClass)}>
                <LogEntry
                  log={log}
                  viewMode={viewMode}
                  strip={strip}
                  slowResponseThresholdSeconds={slowResponseThresholdSeconds}
                  cacheTrend={cacheTrends?.get(log.id) ?? null}
                  onCompareWithPrevious={
                    comparisonPredecessors.has(log.id) ? onCompareWithPrevious : undefined
                  }
                />
              </div>
            </div>
          );
        })
      )}
    </div>
  );
});
