import React, { useState, useEffect, useCallback, useRef } from 'react'
import './components/styles.scss';
import { FilterUsersProps, User } from './types';
import { UserAvatars } from './components/avatarsList';
import { PanelList } from './components/PanelList'

// Re-export types
export * from './types';

export const FilterUsers = (props: FilterUsersProps) => {
  const { 
    usersList = [],
    selectedUsers = [],
    onSelectUsers,
    max, 
    spacing, 
    size, 
    variant, 
    className, 
    onClick,
    fetchMoreUsers,
    isShowVisible,
    onClickShowMore,
    searchUsers,
    surplus,
    messageLoading,
    placeholderInputSearch
  } = props;

  const [displayedUsersList, setDisplayedUsersList] = useState<User[]>(usersList);
  const [isLoading, setIsLoading] = useState(false);
  const [hasMore, setHasMore] = useState(true);
  const [isSearching, setIsSearching] = useState(false);
  const filterUsersRef = useRef<HTMLDivElement>(null);
  
  // Update the displayed user list when usersList prop changes
  useEffect(() => {
    setDisplayedUsersList(usersList);
  }, [usersList]);

  // Use isShowVisible from props if defined, otherwise use internal state
  const [isShowPanel, setIsShowPanel] = useState(isShowVisible === true ? true : false);
  
  // Update internal state when the prop changes
  useEffect(() => {
    if (isShowVisible !== undefined) {
      setIsShowPanel(isShowVisible);
    }
  }, [isShowVisible]);

  // Handler for clicking outside to close panel
  useEffect(() => {
    const handleClickOutside = (event: MouseEvent) => {
      // If panel is not visible, don't do anything
      if (!(isShowVisible !== undefined ? isShowVisible : isShowPanel)) {
        return;
      }

      // Check if click was outside the component
      if (filterUsersRef.current && !filterUsersRef.current.contains(event.target as Node)) {
        // Only change internal state if isShowVisible is not provided
        if (isShowVisible === undefined) {
          setIsShowPanel(false);
        }
        
        // Call onClickShowMore with 0 to indicate closing panel
        if (onClickShowMore) {
          onClickShowMore(0);
        }
      }
    };

    // Add event listener
    document.addEventListener('mousedown', handleClickOutside);
    
    // Remove event listener on cleanup
    return () => {
      document.removeEventListener('mousedown', handleClickOutside);
    };
  }, [isShowVisible, isShowPanel, onClickShowMore]);

  const handleClick = (userId: string) => {
    // Call the original onClick if provided
    if (onClick) {
      onClick(userId);
    }
    
    // Find the user with the clicked ID
    const clickedUser = usersList.find(user => user.id === userId);
    
    if (clickedUser && onSelectUsers) {
      // Check if this user is already selected
      const isAlreadySelected = selectedUsers.some(user => user.id === userId);
      
      if (isAlreadySelected) {
        // Remove the user from selectedUsers
        const newSelectedUsers = selectedUsers.filter(user => user.id !== userId);
        onSelectUsers(newSelectedUsers);
      } else {
        // Add the user to selectedUsers
        const newSelectedUsers = [...selectedUsers, clickedUser];
        onSelectUsers(newSelectedUsers);
      }
    }
  }

  const handleSearchUsers = useCallback((searchTerm: string): Promise<{users: User[], hasMore: boolean}> => {
    if (!searchUsers) {
      return Promise.resolve({ users: [], hasMore: false });
    }
    
    return searchUsers(searchTerm);
  }, [searchUsers]);

  const handleClickShowMore = (surplusValue: number) => {
    // Only change internal state if isShowVisible is not provided
    if (isShowVisible === undefined) {
      setIsShowPanel(!isShowPanel);
    }
    
    // Call external callback if it exists
    if (onClickShowMore) {
      onClickShowMore(surplusValue);
    }
  }
  
  // Function to load more users
  const loadMoreUsers = useCallback(async () => {
    if (!fetchMoreUsers || isLoading || !hasMore || isSearching) {
      return { users: [], hasMore: false };
    }
    
    setIsLoading(true);
    
    try {
      const result = await fetchMoreUsers();
      
      // Update local state with new users
      if (result.users && result.users.length > 0) {
        setDisplayedUsersList(prevUsers => [...prevUsers, ...result.users]);
      }
      
      setHasMore(result.hasMore);
      return result;
    } catch (error) {
      console.error("Error loading more users:", error);
      return { users: [], hasMore: false };
    } finally {
      setIsLoading(false);
    }
  }, [fetchMoreUsers, isLoading, hasMore, isSearching]);
  
  // Check which users are selected to pass to UserAvatars
  const selectedUserIds = selectedUsers.map(user => user.id);
  
  return (
    <div className={`gtc-rc-filter-users ${className || ''}`} ref={filterUsersRef}>
      <div className="filter-users-container">
        <UserAvatars 
          users={usersList} 
          max={max ? max + 1 : 4}
          spacing={spacing}
          size={size}
          variant={variant}
          onClick={handleClick} 
          onClickShowMore={handleClickShowMore}
          selectedUserIds={selectedUserIds}
          isPanelVisible={isShowVisible !== undefined ? isShowVisible : isShowPanel}
          surplus={surplus}
        />
        <PanelList
          usersList={displayedUsersList}
          selectedUsers={selectedUsers}
          onSelectUsers={onSelectUsers || (() => {})}
          isShowVisible={isShowVisible !== undefined ? isShowVisible : isShowPanel}
          fetchMoreUsers={loadMoreUsers}
          searchUsers={handleSearchUsers}
          messageLoading={messageLoading}
          placeholderInputSearch={placeholderInputSearch}
        />
      </div>
    </div>
  )
}