import { useEffect, useRef } from 'react';

export function useChatScroll() {
  const bodyRef = useRef<HTMLDivElement>(null);
  const autoScrollRef = useRef(true);
  const initialScrollDoneRef = useRef(false);
  const scrollRafRef = useRef<number | null>(null);
  const scrollProgrammaticAtRef = useRef(0);
  const lastScrollTopRef = useRef(0);
  const userScrollLockRef = useRef(false);
  const lastUserScrollAtRef = useRef(0);
  const lastUserScrollTypeRef = useRef<string>('');
  const attachRetryTimerRef = useRef<number | null>(null);

  const scrollBottom = (force = false) => {
    if (force) {
      userScrollLockRef.current = false;
      autoScrollRef.current = true;
    }
    if (!force && (!autoScrollRef.current || userScrollLockRef.current)) return;
    if (scrollRafRef.current) {
      cancelAnimationFrame(scrollRafRef.current);
      scrollRafRef.current = null;
    }
    scrollRafRef.current = requestAnimationFrame(() => {
      scrollRafRef.current = null;
      const el = bodyRef.current;
      if (!el) return;
      scrollProgrammaticAtRef.current = Date.now();
      el.scrollTop = el.scrollHeight;
    });
  };

  const cancelAutoScroll = (type: string) => {
    userScrollLockRef.current = true;
    autoScrollRef.current = false;
    lastUserScrollAtRef.current = Date.now();
    lastUserScrollTypeRef.current = type;
    if (scrollRafRef.current) {
      cancelAnimationFrame(scrollRafRef.current);
      scrollRafRef.current = null;
    }
  };

  useEffect(() => {
    let destroyed = false;
    let detach: (() => void) | null = null;

    const attach = (el: HTMLDivElement) => {
      const onScroll = () => {
        const now = Date.now();
        const isProgrammatic = now - scrollProgrammaticAtRef.current < 50;
        const nextTop = el.scrollTop;
        const lastTop = lastScrollTopRef.current;
        const distance = el.scrollHeight - nextTop - el.clientHeight;

        const scrollDelta = nextTop - lastTop;
        if (scrollDelta < 0) {
          cancelAutoScroll(isProgrammatic ? 'scroll(up)+programmatic' : 'scroll(up)');
        }
        lastScrollTopRef.current = nextTop;

        if (distance < 8) {
          if (!userScrollLockRef.current) {
            userScrollLockRef.current = false;
          } else if (!isProgrammatic && scrollDelta > 5) {
            userScrollLockRef.current = false;
          }
        }
        autoScrollRef.current = distance < 32 && !userScrollLockRef.current;
        if ((!autoScrollRef.current || userScrollLockRef.current) && scrollRafRef.current) {
          cancelAnimationFrame(scrollRafRef.current);
          scrollRafRef.current = null;
        }
      };

      const onWindowWheelCapture = (e: WheelEvent) => {
        const target = e.target as Node | null;
        if (!target) return;
        const within = el.contains(target);
        if (within) cancelAutoScroll('wheel');
      };

      el.addEventListener('scroll', onScroll, { passive: true });
      window.addEventListener('wheel', onWindowWheelCapture, { passive: true, capture: true });
      setTimeout(onScroll, 100);

      detach = () => {
        el.removeEventListener('scroll', onScroll);
        window.removeEventListener('wheel', onWindowWheelCapture, { capture: true } as any);
      };
    };

    const tryAttach = () => {
      if (destroyed) return;
      const el = bodyRef.current;
      if (!el) {
        attachRetryTimerRef.current = window.setTimeout(tryAttach, 200);
        return;
      }
      attach(el);
    };

    tryAttach();

    return () => {
      destroyed = true;
      if (attachRetryTimerRef.current) {
        window.clearTimeout(attachRetryTimerRef.current);
        attachRetryTimerRef.current = null;
      }
      detach?.();
    };
  }, []);

  return {
    bodyRef,
    scrollBottom,
    initialScrollDoneRef,
    autoScrollRef,
    userScrollLockRef
  };
}
