import { useCallback, useMemo } from 'react';
import { unstable_batchedUpdates } from 'react-dom';
import { useSmartLinkContext } from '@atlaskit/link-provider';
import { ACTION_ERROR, ACTION_ERROR_FALLBACK, ACTION_RELOADING, ACTION_RESOLVED, ACTION_UPDATE_METADATA_STATUS, APIError, cardAction, getStatus } from '@atlaskit/linking-common';
import { fg } from '@atlaskit/platform-feature-flags';
import { SmartLinkStatus } from '../../../constants';
import { getUnauthorizedJsonLd } from '../../../utils/jsonld';
import { ERROR_MESSAGE_FATAL, ERROR_MESSAGE_METADATA, ERROR_MESSAGE_OAUTH } from '../../actions/constants';
var useResponse = function useResponse() {
  // Takes in the JSON-LD response and dispatch the resolved action for the card.
  // It will dispatch a successful or error action
  var _useSmartLinkContext = useSmartLinkContext(),
    store = _useSmartLinkContext.store,
    config = _useSmartLinkContext.config;
  var getState = store.getState,
    dispatch = store.dispatch;
  var hasAuthFlowSupported = config.authFlow !== 'disabled';
  var setMetadataStatus = useCallback(function (url, metadataStatus) {
    dispatch(cardAction(ACTION_UPDATE_METADATA_STATUS, {
      url: url
    }, undefined, undefined, metadataStatus));
  }, [dispatch]);
  var handleResolvedLinkError = useCallback(function (url, error, response, isMetadataRequest) {
    var newState = {
      status: SmartLinkStatus.Pending,
      details: undefined
    };
    var _ref = getState()[url] || newState,
      details = _ref.details;
    var hasData = !!(details && details.data);

    // If metadata request then set metadata status, return and do not alter link status
    if (isMetadataRequest) {
      setMetadataStatus(url, 'errored');
      return;
    }
    if (error.kind === 'fatal') {
      // If we already have resolved data for this URL in the store, then
      // simply fallback to the previous data.
      if (hasData) {
        dispatch(cardAction(ACTION_RESOLVED, {
          url: url
        }, details));

        // If there's no previous data in the store for this URL, then bail
        // out and let the editor handle fallbacks (returns to a blue link).
      } else {
        dispatch(cardAction(ACTION_ERROR, {
          url: url
        }, details, error));
        throw error;
      }

      // Handle AuthErrors (user did not have access to resource) -
      // Missing AAID in ASAP claims, or missing UserContext, or 403 from downstream
    } else if (error.kind === 'auth') {
      dispatch(cardAction(ACTION_RESOLVED, {
        url: url
      }, getUnauthorizedJsonLd()));
    } else {
      if (error.kind === 'fallback') {
        // Fallback to blue link with smart link formatting. Not part of reliability.
        dispatch(cardAction(ACTION_ERROR_FALLBACK, {
          url: url
        }, response, error));
      } else {
        // Fallback to blue link with smart link formatting. Part of reliability.
        dispatch(cardAction(ACTION_ERROR, {
          url: url
        }, undefined, error));
      }
    }
  }, [getState, setMetadataStatus, dispatch]);
  var handleResolvedLinkSuccess = useCallback(function (resourceUrl, response, isReloading, isMetadataRequest) {
    var metadataStatus = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 'resolved';
    // Some optimized resolves intentionally leave metadata pending so hover can fetch it.
    // Check response status before evaluating the feature gate so non-resolved responses
    // do not fire a gate exposure when the gate result would be ignored.
    var shouldUseProvidedMetadataStatus = getStatus(response) === 'resolved' && fg('platform_smartlink_inline_resolve_optimization');
    setMetadataStatus(resourceUrl, shouldUseProvidedMetadataStatus ? metadataStatus : 'resolved');
    // Dispatch Analytics and resolved card action - including unauthorized states.
    if (isReloading) {
      dispatch(cardAction(ACTION_RELOADING, {
        url: resourceUrl
      }, response));
    } else {
      dispatch(cardAction(ACTION_RESOLVED, {
        url: resourceUrl
      }, response, undefined, undefined, isMetadataRequest));
    }
  }, [setMetadataStatus, dispatch]);
  var handleResolvedLinkResponse = useCallback(function (resourceUrl, response) {
    var isReloading = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
    var isMetadataRequest = arguments.length > 3 ? arguments[3] : undefined;
    var metadataStatus = arguments.length > 4 ? arguments[4] : undefined;
    if (!resourceUrl) {
      return;
    }
    var hostname = new URL(resourceUrl).hostname;
    var nextStatus = response ? getStatus(response) : 'fatal';

    // If we require authorization & do not have an authFlow available,
    // throw an error and render as a normal blue link.
    if ((nextStatus === 'unauthorized' || nextStatus === 'forbidden') && !hasAuthFlowSupported) {
      handleResolvedLinkError(resourceUrl, new APIError('fallback', hostname, ERROR_MESSAGE_OAUTH), response, isMetadataRequest);
      return;
    }

    // Handle any other errors
    if (!response || nextStatus === 'fatal') {
      handleResolvedLinkError(resourceUrl, new APIError('fatal', hostname, ERROR_MESSAGE_FATAL), undefined, isMetadataRequest);
      return;
    }

    // Handle errors of any other kind in the metadata request response
    if (isMetadataRequest && nextStatus !== 'resolved') {
      handleResolvedLinkError(resourceUrl, new APIError('error', hostname, ERROR_MESSAGE_METADATA), response, isMetadataRequest);
      return;
    }

    /**
     * Using unstable_batchedUpdates because this store update happens async and triggers a rerender
     * more info:
     * https://github.com/facebook/react/blob/v18.2.0/packages/use-sync-external-store/src/useSyncExternalStoreShimClient.js#L113
     * https://react-redux.js.org/api/batch
     */
    unstable_batchedUpdates(function () {
      handleResolvedLinkSuccess(resourceUrl, response, isReloading, isMetadataRequest, metadataStatus);
    });
  }, [handleResolvedLinkError, handleResolvedLinkSuccess, hasAuthFlowSupported]);
  return useMemo(function () {
    return {
      handleResolvedLinkError: handleResolvedLinkError,
      handleResolvedLinkResponse: handleResolvedLinkResponse
    };
  }, [handleResolvedLinkError, handleResolvedLinkResponse]);
};
export default useResponse;