// Dependencies
import React from 'react';

// Dtos
import { UserCredentials, Session } from '@src/chatClient/dto/authentication';
import { AppCredentials, AppConfig } from '@src/chatClient/dto/app';
import { UserCreate } from '@src/chatClient/dto/user.create';

// Chat Client
import chatClient from '../../chatClient';

/**
 * Props definition of {@link AuthContext}
 * @interface AuthContextType
 */
export interface AuthContextType {
  session?: Session;
  isInitAuth: boolean;
  signIn: (userCredentials: UserCredentials) => void;
  signOut: () => void;
  signUp: (user: UserCreate) => void;
}

/**
 * Auth context.
 */
export const AuthContext = React
  .createContext<AuthContextType>({ isInitAuth: false } as AuthContextType);

/**
 * Props definition of {@link ChatProvider}
 * @interface ChatProviderProps
 */
export interface ChatProviderProps {
  children: React.ReactNode,
  credentials: AppCredentials,
  config?: AppConfig,
}

/**
 * Chat provider component.
 * @param props The properties of component.
 * @returns The chat provider.
 */
export function ChatProvider(props: ChatProviderProps): React.ReactElement {
  const { children, credentials, config } = props;
  const [session, setSession] = React.useState<Session>();
  const [isInitAuth, setInitAuth] = React.useState(false);

  React.useEffect(() => {
    setInitAuth(true);
    chatClient
      .init(credentials, config)
      .then(() => chatClient.auth.validateSession())
      .then(setSession)
      .finally(() => setInitAuth(false));
  }, [credentials, config]);

  const { current: authContext } = React.useRef({
    async signIn(userCredentials: UserCredentials) {
      const currentSession = await chatClient.auth.signIn(userCredentials);
      const { user } = currentSession;
      await chatClient.chat.connect(user.id, userCredentials.password);
      setSession(currentSession);
      return currentSession;
    },
    async signOut() {
      await chatClient.auth.signOut();
      setSession(undefined);
    },
    signUp(user: UserCreate) {
      return chatClient.users.signUp(user);
    },
  });

  return (
    <AuthContext.Provider value={{ ...authContext, session, isInitAuth }}>
      {children}
    </AuthContext.Provider>
  );
}

export default ChatProvider;
