import { useRecoilValue } from 'recoil';
import { useCallback, useRef, useEffect } from 'react';
import { LocalStorageKeys, isAssistantsEndpoint } from 'librechat-data-provider';
import { useGetModelsQuery, useGetEndpointsQuery } from 'librechat-data-provider/react-query';
import type {
  TPreset,
  TModelsConfig,
  TConversation,
  TEndpointsConfig,
} from 'librechat-data-provider';
import type { SetterOrUpdater } from 'recoil';
import type { AssistantListItem } from '~/common';
import { getEndpointField, buildDefaultConvo, getDefaultEndpoint } from '~/utils';
import useAssistantListMap from '~/hooks/Assistants/useAssistantListMap';
import { mainTextareaId } from '~/common';
import store from '~/store';

const useGenerateConvo = ({
  index = 0,
  rootIndex,
  setConversation,
}: {
  index?: number;
  rootIndex: number;
  setConversation?: SetterOrUpdater<TConversation | null>;
}) => {
  const modelsQuery = useGetModelsQuery();
  const assistantsListMap = useAssistantListMap();
  const { data: endpointsConfig = {} as TEndpointsConfig } = useGetEndpointsQuery();

  const timeoutIdRef = useRef<NodeJS.Timeout>();
  const rootConvo = useRecoilValue(store.conversationByKeySelector(rootIndex));

  useEffect(() => {
    if (rootConvo?.conversationId && setConversation) {
      setConversation((prevState) => {
        if (!prevState) {
          return prevState;
        }
        const update = {
          ...prevState,
          conversationId: rootConvo.conversationId,
        } as TConversation;

        return update;
      });
    }
  }, [rootConvo?.conversationId, setConversation]);

  const generateConversation = useCallback(
    ({
      template = {},
      preset,
      modelsData,
    }: {
      template?: Partial<TConversation>;
      preset?: Partial<TPreset>;
      modelsData?: TModelsConfig;
    } = {}) => {
      let conversation = {
        conversationId: 'new',
        title: 'New Chat',
        endpoint: null,
        ...template,
        createdAt: '',
        updatedAt: '',
      };

      if (rootConvo?.conversationId) {
        conversation.conversationId = rootConvo.conversationId;
      }

      const modelsConfig = modelsData ?? modelsQuery.data;

      const defaultEndpoint = getDefaultEndpoint({
        convoSetup: preset ?? conversation,
        endpointsConfig,
      });

      const endpointType = getEndpointField(endpointsConfig, defaultEndpoint, 'type');
      if (!conversation.endpointType && endpointType) {
        conversation.endpointType = endpointType;
      } else if (conversation.endpointType && !endpointType) {
        conversation.endpointType = undefined;
      }

      const isAssistantEndpoint = isAssistantsEndpoint(defaultEndpoint);
      const assistants: AssistantListItem[] = assistantsListMap[defaultEndpoint] ?? [];

      if (
        conversation.assistant_id &&
        !assistantsListMap[defaultEndpoint]?.[conversation.assistant_id]
      ) {
        conversation.assistant_id = undefined;
      }

      if (!conversation.assistant_id && isAssistantEndpoint) {
        conversation.assistant_id =
          localStorage.getItem(`${LocalStorageKeys.ASST_ID_PREFIX}${index}${defaultEndpoint}`) ??
          assistants[0]?.id;
      }

      if (
        conversation.assistant_id &&
        isAssistantEndpoint &&
        conversation.conversationId === 'new'
      ) {
        const assistant = assistants.find((asst) => asst.id === conversation.assistant_id);
        conversation.model = assistant?.model;
      }

      if (conversation.assistant_id && !isAssistantEndpoint) {
        conversation.assistant_id = undefined;
      }

      const models = modelsConfig?.[defaultEndpoint] ?? [];
      conversation = buildDefaultConvo({
        conversation,
        lastConversationSetup: preset as TConversation,
        endpoint: defaultEndpoint,
        models,
      });

      if (preset?.title) {
        conversation.title = preset.title;
      }

      if (setConversation) {
        setConversation(conversation);
      }

      clearTimeout(timeoutIdRef.current);
      timeoutIdRef.current = setTimeout(() => {
        const textarea = document.getElementById(mainTextareaId);
        if (textarea) {
          textarea.focus();
        }
      }, 150);
      return conversation;
    },
    [assistantsListMap, endpointsConfig, index, modelsQuery.data, rootConvo, setConversation],
  );

  return { generateConversation };
};

export default useGenerateConvo;
