import React, { useEffect, useRef, useState, useCallback } from 'react';
import styles from './AutoScroll.module.css';

export interface AutoScrollProps {
  /**
   * Children to render inside the scrollable container
   */
  children: React.ReactNode;
  
  /**
   * Optional className for the container
   */
  className?: string;
  
  /**
   * Dependency array to watch for changes that should trigger auto-scroll
   * Typically the length of the items array or a unique identifier
   */
  scrollDependency?: any;
  
  /**
   * Threshold in pixels from bottom to consider user "at bottom"
   * @default 100
   */
  threshold?: number;
  
}

/**
 * AutoScroll component that automatically scrolls to the bottom when new content is added,
 * unless the user has scrolled up. Shows a button when user has scrolled up.
 */
const AutoScroll: React.FC<AutoScrollProps> = ({
  children,
  className = '',
  scrollDependency,
  threshold = 100
}) => {
  const containerRef = useRef<HTMLDivElement>(null);
  const [showNewMessageButton, setShowNewMessageButton] = useState(false);
  const [isUserScrolling, setIsUserScrolling] = useState(false);
  const scrollTimeoutRef = useRef<NodeJS.Timeout | null>(null);
  const lastScrollDependencyRef = useRef<any>(scrollDependency);
  const isScrollingProgrammaticallyRef = useRef(false);

  // Check if user is near the bottom of the scroll container
  const isNearBottom = useCallback((): boolean => {
    const container = containerRef.current;
    if (!container) return true;

    const { scrollTop, scrollHeight, clientHeight } = container;
    const distanceFromBottom = scrollHeight - scrollTop - clientHeight;
    return distanceFromBottom <= threshold;
  }, [threshold]);

  // Scroll to bottom
  const scrollToBottom = useCallback((smooth: boolean = true) => {
    const container = containerRef.current;
    if (!container) return;

    isScrollingProgrammaticallyRef.current = true;
    container.scrollTo({
      top: container.scrollHeight,
      behavior: smooth ? 'smooth' : 'auto'
    });

    // Reset flag and update button visibility after scroll completes
    setTimeout(() => {
      isScrollingProgrammaticallyRef.current = false;
      setShowNewMessageButton(!isNearBottom());
    }, smooth ? 500 : 100);
  }, [isNearBottom]);

  // Handle scroll events
  const handleScroll = useCallback(() => {
    // Ignore programmatic scrolling
    if (isScrollingProgrammaticallyRef.current) {
      return;
    }

    // Clear existing timeout
    if (scrollTimeoutRef.current) {
      clearTimeout(scrollTimeoutRef.current);
    }

    // Mark that user is scrolling
    setIsUserScrolling(true);

    // Check if user is near bottom
    const nearBottom = isNearBottom();
    
    // Always show button when scrolled up
    setShowNewMessageButton(!nearBottom);

    // Reset user scrolling flag after a delay
    scrollTimeoutRef.current = setTimeout(() => {
      setIsUserScrolling(false);
    }, 150);
  }, [isNearBottom]);

  // Auto-scroll when content changes
  useEffect(() => {
    const container = containerRef.current;
    if (!container) return;

    const hasNewContent = scrollDependency !== lastScrollDependencyRef.current;
    lastScrollDependencyRef.current = scrollDependency;

    // Only auto-scroll if:
    // 1. There's new content
    // 2. User is not currently scrolling
    // 3. User is near the bottom (or was near bottom before new content)
    if (hasNewContent && !isUserScrolling) {
      if (isNearBottom()) {
        // User is at bottom, scroll to show new content
        scrollToBottom(true);
        setShowNewMessageButton(false);
      } else {
        // User has scrolled up, show button
        setShowNewMessageButton(true);
      }
    } else if (!isUserScrolling) {
      // Check scroll position even if no new content (to update button visibility)
      setShowNewMessageButton(!isNearBottom());
    }
  }, [scrollDependency, isUserScrolling, isNearBottom, scrollToBottom]);

  // Handle new message button click
  const handleNewMessageClick = useCallback(() => {
    scrollToBottom(true);
    setShowNewMessageButton(false);
  }, [scrollToBottom]);

  // Initial scroll to bottom on mount and check scroll position
  useEffect(() => {
    if (containerRef.current) {
      scrollToBottom(false);
      // Check scroll position after a brief delay to ensure DOM is ready
      setTimeout(() => {
        setShowNewMessageButton(!isNearBottom());
      }, 100);
    }
  }, [scrollToBottom, isNearBottom]);

  return (
    <div className={`${styles.autoScrollContainer} ${className}`}>
      {showNewMessageButton && (
        <button
          className={styles.scrollToBottomButton}
          onClick={handleNewMessageClick}
          aria-label="Scroll to bottom"
        >
          <span className={styles.scrollArrow}>↓</span>
        </button>
      )}
      <div
        ref={containerRef}
        className={styles.scrollableContent}
        onScroll={handleScroll}
      >
        {children}
      </div>
    </div>
  );
};

export default AutoScroll;

