import { useEffect, useState } from 'react';
import { ChevronRight, CheckCircle2 } from 'lucide-react';
import type { ChatMessage } from '../types';
import type { FoldCounts } from './turn-rows';
import { foldLabel, keyOf } from './turn-rows';
import { COLLAPSE_MS } from './fold-exit';
import { MessageBubble } from './MessageBubble';

type TurnFoldProps = {
  messages: ChatMessage[];
  counts: FoldCounts;
  open: boolean;
  /**
   * Expand the tool rows inside. Set only while this fold is closing over work you were watching a moment
   * ago, so it shrinks from what was actually on your screen rather than snapping to a collapsed copy of it.
   */
  childrenOpen?: boolean;
  onToggle: () => void;
};

/**
 * One turn's work, collapsed to a line.
 *
 * The failure count is on the summary rather than only inside, because a red row you have to open to find
 * is a red row you never find. It is also the shared handle: "the one where the tsgo call went red" has to
 * be sayable without either of us expanding anything.
 */
export const TurnFold = ({ messages, counts, open, childrenOpen, onToggle }: TurnFoldProps) => {
  // The content has to outlive the close by the length of the animation. A fold that unmounts its work on
  // the same frame it closes has nothing left to shrink, so it vanishes instead of collapsing — which is
  // exactly the jump this is here to remove.
  const [keep, setKeep] = useState(false);
  useEffect(() => {
    if (open) {
      setKeep(true);
      return;
    }
    if (!keep) return;
    const timer = setTimeout(() => setKeep(false), COLLAPSE_MS);
    return () => clearTimeout(timer);
  }, [open, keep]);

  return (
    <div className="my-1">
      <button
        type="button"
        onClick={onToggle}
        aria-expanded={open}
        className={`flex w-full cursor-pointer items-center gap-2 rounded-md px-3 py-1 text-left text-xs transition-colors ${
          counts.failed
            ? 'text-destructive hover:bg-destructive/10'
            : 'text-muted-foreground hover:bg-muted hover:text-foreground'
        }`}
      >
        <ChevronRight className={`h-3 w-3 shrink-0 transition-transform ${open ? 'rotate-90' : ''}`} />
        <span className="h-px flex-1 bg-border" />
        <span className="shrink-0 tabular-nums">{foldLabel(counts)}</span>
        <span className="h-px flex-1 bg-border" />
      </button>

      {/* `0fr` → `1fr` is the one way to animate to a height nobody can know in advance — a turn's work is
          whatever it is. The inner `overflow-hidden` is what makes the row clip rather than spill while the
          track shrinks, and the virtualiser's own ResizeObserver follows the height down, so the rows below
          ride the animation instead of teleporting when it ends. */}
      <div
        className="grid transition-[grid-template-rows] ease-out"
        style={{ gridTemplateRows: open ? '1fr' : '0fr', transitionDuration: `${COLLAPSE_MS}ms` }}
      >
        <div className="overflow-hidden">
          {(open || keep) && (
            <div className="mt-1 space-y-1.5 border-l-2 border-border pl-2">
              {/* Keyed by identity, not position: folded work is where an opened tool row is most likely to
                  be re-ordered under you by a prepend, and an index key reattaches it to whatever now sits
                  there. */}
              {messages.map((message, i) => (
                <MessageBubble key={keyOf(message, i)} message={message} defaultOpen={childrenOpen} />
              ))}
            </div>
          )}
        </div>
      </div>
    </div>
  );
};

/**
 * A turn that ended without a closing message. Written as a seam, never as prose — see `turn-rows.ts`.
 */
export const TurnEnd = () => (
  <div className="flex items-center gap-3 py-2 text-muted-foreground select-none">
    <div className="h-px flex-1 bg-border" />
    <span className="flex items-center gap-1.5 text-[11px] font-medium tracking-wide uppercase">
      <CheckCircle2 className="h-3 w-3" />
      Turn finished · no closing message
    </span>
    <div className="h-px flex-1 bg-border" />
  </div>
);
