import { useEffect, useRef, useState } from 'react';

/** How close to the bottom edge (in px) still counts as "already at the bottom" (§3.2). */
const NEAR_BOTTOM_THRESHOLD_PX = 120;

export interface UseThreadScrollResult {
  /** Attach to a zero-height sentinel element rendered after the last message. */
  bottomRef: (node: HTMLDivElement | null) => void;
  /** A floating «پیام جدید ↓» pill should render while this is true. */
  showNewMessagePill: boolean;
  /** Scrolls to the newest message and dismisses the pill (the pill's own tap handler). */
  scrollToNewest: () => void;
}

/**
 * Chat scroll orchestration (§3.2), reusable across any message-list surface (this thread now; phase 11's
 * admin thread scrollbox next — it has the inverse bug, opening scrolled to the top). A thread opens
 * scrolled to the **newest** message; sending always scrolls to the new bubble; receiving auto-scrolls only
 * when the viewer is already near the bottom, otherwise shows a dismissible "new message" pill.
 *
 * Uses an `IntersectionObserver` on a bottom sentinel (not a tracked scroll container) so it works whether
 * the *page* scrolls or an inner box does — the observer's root is the viewport by default, which correctly
 * accounts for whichever ancestor actually scrolls. Guarded for environments without
 * `IntersectionObserver` (e.g. jsdom in tests): it degrades to "always treat as near the bottom".
 */
export function useThreadScroll(messageCount: number, lastMessageIsMine: boolean): UseThreadScrollResult {
  const [showNewMessagePill, setShowNewMessagePill] = useState(false);
  const sentinelRef = useRef<HTMLDivElement | null>(null);
  const isNearBottomRef = useRef(true);
  const didInitialScrollRef = useRef(false);
  const prevCountRef = useRef(0);

  const scrollToNewest = () => {
    sentinelRef.current?.scrollIntoView({ behavior: 'smooth', block: 'end' });
    setShowNewMessagePill(false);
  };

  const bottomRef = (node: HTMLDivElement | null) => {
    sentinelRef.current = node;
  };

  useEffect(() => {
    const node = sentinelRef.current;
    if (!node || typeof IntersectionObserver === 'undefined') return undefined;
    const observer = new IntersectionObserver(
      ([entry]) => {
        isNearBottomRef.current = entry.isIntersecting;
        if (entry.isIntersecting) setShowNewMessagePill(false);
      },
      { rootMargin: `0px 0px ${NEAR_BOTTOM_THRESHOLD_PX}px 0px` },
    );
    observer.observe(node);
    return () => observer.disconnect();
  }, []);

  useEffect(() => {
    if (messageCount === 0) return;
    if (!didInitialScrollRef.current) {
      // Opens at the newest message (§3.2) — instant, no animation, on first load.
      sentinelRef.current?.scrollIntoView({ behavior: 'auto', block: 'end' });
      didInitialScrollRef.current = true;
      prevCountRef.current = messageCount;
      return;
    }
    if (messageCount > prevCountRef.current) {
      if (lastMessageIsMine || isNearBottomRef.current) {
        sentinelRef.current?.scrollIntoView({ behavior: 'smooth', block: 'end' });
        setShowNewMessagePill(false);
      } else {
        setShowNewMessagePill(true);
      }
    }
    prevCountRef.current = messageCount;
  }, [messageCount, lastMessageIsMine]);

  return { bottomRef, showNewMessagePill, scrollToNewest };
}
