import { createContext, useContext, useMemo, useState, type ReactNode } from 'react';

/**
 * Which tool rows you have opened or closed by hand, held above the rows themselves.
 *
 * Rows are virtualised, so a row unmounting is not the call ending and remounting is not a new call. State
 * kept inside the row is thrown away the moment it scrolls past the overscan window — which is exactly the
 * reasoning that already lifted the turn folds out of `TurnFold` and into `MessageList`. The tool rows were
 * left behind, so scrolling away from a call you had expanded, or any re-render that shifted the list,
 * silently closed it again.
 *
 * Only your explicit clicks live here. The default — open while you are watching the turn happen, collapsed
 * once you have moved on — is derived per row from the transcript, so there is nothing to seed, invalidate
 * or clean up, and a reload renders the same rows as a live session.
 */
type ToolOpenStore = {
  isOpen: (id: string, fallback: boolean) => boolean;
  /** `current` is what the row is showing now, so a click means "the opposite of that" regardless of why. */
  toggle: (id: string, current: boolean) => void;
};

const ToolOpenContext = createContext<ToolOpenStore | null>(null);

export const ToolOpenProvider = ({ children }: { children: ReactNode }) => {
  const [overrides, setOverrides] = useState<ReadonlyMap<string, boolean>>(() => new Map());

  const store = useMemo<ToolOpenStore>(
    () => ({
      isOpen: (id, fallback) => overrides.get(id) ?? fallback,
      toggle: (id, current) =>
        setOverrides((prev) => {
          const next = new Map(prev);
          next.set(id, !current);
          return next;
        }),
    }),
    [overrides],
  );

  return <ToolOpenContext.Provider value={store}>{children}</ToolOpenContext.Provider>;
};

/**
 * A row's open state and its toggle.
 *
 * Falls back to component-local state when no provider is above it, so a `ToolActivity` rendered outside the
 * message list still expands — it just doesn't survive being unmounted, which outside a virtualised list it
 * isn't.
 */
export function useToolOpen(id: string, defaultOpen: boolean): [boolean, () => void] {
  const store = useContext(ToolOpenContext);
  const [local, setLocal] = useState<boolean | null>(null);
  const open = store ? store.isOpen(id, defaultOpen) : (local ?? defaultOpen);
  return [open, () => (store ? store.toggle(id, open) : setLocal(!open))];
}
