import { useCallback, useEffect, useRef } from 'react';
import { useUserManagerStore } from './userStore';
import { userManager } from './UserManager';
import type { UserDTO } from '../../types/dto';
import { useAuthStore } from '../auth/authStore';

export interface UseCurrentUserResult {
  user: UserDTO | null;
  isLoading: boolean;
  refresh: () => Promise<UserDTO | null>;
}

export function useCurrentUser(): UseCurrentUserResult {
  const user = useUserManagerStore(state => state.currentUser);
  const isLoading = useUserManagerStore(state => state.isLoadingCurrentUser);
  const lastFetchedRef = useRef<string | null>(null);

  useEffect(() => {
    const authUser = useAuthStore.getState().currentUser;
    const userId = authUser?.id;
    if (userId && lastFetchedRef.current !== userId) {
      lastFetchedRef.current = userId;
      useUserManagerStore.getState().setLoadingCurrentUser(true);
      userManager.getCurrentUser().finally(() => {
        useUserManagerStore.getState().setLoadingCurrentUser(false);
      });
    }
  }, []);

  useEffect(() => {
    return useAuthStore.subscribe((state, prev) => {
      if (!state.currentUser && prev.currentUser) {
        lastFetchedRef.current = null;
      }
    });
  }, []);

  const refresh = useCallback(async () => {
    useUserManagerStore.getState().setLoadingCurrentUser(true);
    try {
      return await userManager.getCurrentUser(true);
    } finally {
      useUserManagerStore.getState().setLoadingCurrentUser(false);
    }
  }, []);

  return { user, isLoading, refresh };
}

export interface UseUserResult {
  user: UserDTO | null;
  isLoading: boolean;
  refresh: () => Promise<UserDTO | null>;
}

export function useUser(userId: string | undefined | null): UseUserResult {
  const user = useUserManagerStore(state =>
    userId ? (state.usersMap.get(userId)?.data ?? null) : null
  );
  const isLoading = useUserManagerStore(state =>
    userId ? state.loadingUserIds.has(userId) : false
  );
  const lastFetchedRef = useRef<string | null>(null);

  useEffect(() => {
    if (!userId) return;
    if (lastFetchedRef.current !== userId) {
      lastFetchedRef.current = userId;
      useUserManagerStore.getState().setLoadingUser(userId, true);
      userManager.getUserById(userId).finally(() => {
        useUserManagerStore.getState().setLoadingUser(userId, false);
      });
    }
  }, [userId]);

  const refresh = useCallback(async () => {
    if (!userId) return null;
    useUserManagerStore.getState().setLoadingUser(userId, true);
    try {
      return await userManager.getUserById(userId, true);
    } finally {
      useUserManagerStore.getState().setLoadingUser(userId, false);
    }
  }, [userId]);

  return { user, isLoading, refresh };
}

export interface UseUsersResult {
  getUser: (id: string) => UserDTO | null;
  refreshUser: (id: string) => Promise<UserDTO | null>;
}

export function useUsers(userIds: string[]): UseUsersResult {
  const usersMap = useUserManagerStore(state => state.usersMap);
  const loadingUserIds = useUserManagerStore(state => state.loadingUserIds);
  const fetchedIdsRef = useRef<Set<string>>(new Set());

  useEffect(() => {
    userIds.forEach(id => {
      if (!fetchedIdsRef.current.has(id) && !loadingUserIds.has(id)) {
        fetchedIdsRef.current = new Set(fetchedIdsRef.current).add(id);
        useUserManagerStore.getState().setLoadingUser(id, true);
        userManager.getUserById(id).finally(() => {
          useUserManagerStore.getState().setLoadingUser(id, false);
        });
      }
    });
  }, [userIds, loadingUserIds]);

  const getUser = useCallback((id: string) => {
    return usersMap.get(id)?.data ?? null;
  }, [usersMap]);

  const refreshUser = useCallback(async (id: string) => {
    useUserManagerStore.getState().setLoadingUser(id, true);
    try {
      return await userManager.getUserById(id, true);
    } finally {
      useUserManagerStore.getState().setLoadingUser(id, false);
    }
  }, []);

  return { getUser, refreshUser };
}