import { client } from '@farfetch/blackout-client';
import { usePrevious } from '../../helpers/index.js';
import AuthenticationContext from './AuthenticationContext.js';
import React, { useCallback, useEffect, useRef, useState } from 'react';
import setAuthenticationInterceptors from './helpers/setAuthenticationInterceptors.js';
import useUserAuthState from '../hooks/useUserAuthState.js';
import { jsx as _jsx } from "react/jsx-runtime";
export let CallbackNames;
(function (CallbackNames) {
  CallbackNames["OnUserSessionTerminated"] = "onUserSessionTerminated";
})(CallbackNames || (CallbackNames = {}));
/**
 * Provides support for transparent authentication to apps with access tokens by
 * installing an interceptor on the default \@farfetch/blackout-client axios
 * instance used by all clients. It also provides functions to login/logout a user
 * through the useAuthentication hook that must be called in order for the
 * interceptor to know when to use guest/authenticated user tokens for subsequent
 * requests. See the options below for more information on how you can configure
 * this provider.
 *
 * @example <caption>Adding the AuthenticationProvider to your app</caption>
 * ```
 *
 * import \{ AuthenticationProvider \} from '\@farfetch/blackout-react/authentication/contexts';
 *
 * const App = () =\> \{
 * return (<AuthenticationProvider><MyComponent /></AuthenticationProvider>);
 * \}
 * ```
 *
 * @param props - Props to configure AuthenticationProvider.
 *
 * @returns The authentication context provider element wrapping the passed in children.
 */
function AuthenticationProvider({
  baseURL,
  children,
  headers,
  callbacks,
  ...tokenManagerOptions
}) {
  const [activeTokenData, setActiveTokenData] = useState(null);
  const baseURLRef = useRef(null);
  const headersRef = useRef(null);
  if (baseURLRef.current !== baseURL) {
    client.defaults.baseURL = baseURL;
    baseURLRef.current = baseURL;
  }
  if (headersRef.current !== headers) {
    client.defaults.headers.common = headers;
    headersRef.current = headers;
  }
  const [tokenManager] = useState(() => {
    const tokenManagerInstance = setAuthenticationInterceptors(client, tokenManagerOptions);
    return tokenManagerInstance;
  });
  const authState = useUserAuthState({
    activeTokenData,
    tokenManager
  });
  const clearTokenData = useCallback(() => {
    tokenManager.clearData();
  }, [tokenManager]);
  const setGuestTokensContext = useCallback(context => {
    tokenManager.setGuestTokensContext(context);
  }, [tokenManager]);
  const resetGuestTokensContext = useCallback(() => {
    tokenManager.resetGuestTokensContext();
  }, [tokenManager]);
  const getCurrentGuestTokensContext = useCallback(() => {
    return tokenManager.getCurrentGuestTokensContext();
  }, [tokenManager]);
  const getAccessToken = useCallback(useCache => {
    return tokenManager.getAccessToken(useCache);
  }, [tokenManager]);
  const setGuestUserClaims = useCallback(async (claims, useCache) => {
    await tokenManager.setGuestTokensContext(claims);
    return tokenManager.getAccessToken(useCache);
  }, [tokenManager]);
  const onUserSessionTerminatedEventListener = useCallback(expiredUserToken => {
    const onUserSessionTerminatedCallback = callbacks[CallbackNames.OnUserSessionTerminated];
    if (typeof onUserSessionTerminatedCallback === 'function') {
      onUserSessionTerminatedCallback(expiredUserToken);
    }
  }, [callbacks]);
  const onActiveTokenChangedEventListener = useCallback(newActiveTokenData => {
    setActiveTokenData(newActiveTokenData);
  }, []);
  const previousTokenManager = usePrevious(tokenManager);
  useEffect(() => {
    if (previousTokenManager === tokenManager) {
      return;
    }
    if (!!previousTokenManager) {
      previousTokenManager.setActiveTokenDataChangedEventListener(null);
      previousTokenManager.setUserSessionTerminatedEventListener(null);
    }
    if (tokenManager) {
      tokenManager.setActiveTokenDataChangedEventListener(onActiveTokenChangedEventListener);
      tokenManager.setUserSessionTerminatedEventListener(onUserSessionTerminatedEventListener);
      if (!tokenManager.isLoaded) {
        tokenManager.load();
      }
    }
  }, [onActiveTokenChangedEventListener, onUserSessionTerminatedEventListener, previousTokenManager, tokenManager]);
  const values = {
    activeTokenData,
    clearTokenData,
    getAccessToken,
    getCurrentGuestTokensContext,
    resetGuestTokensContext,
    setGuestTokensContext,
    setGuestUserClaims,
    tokenManager,
    // Remove tokenManager when the post guestTokens endpoint returns the userId in the response
    ...authState
  };
  return /*#__PURE__*/_jsx(AuthenticationContext.Provider, {
    value: values,
    children: children
  });
}
export default AuthenticationProvider;