import React, { useCallback, useEffect, useMemo, useRef } from 'react';
import { useAnalyticsEvents as useAnalyticsEventsNext } from '@atlaskit/analytics-next';
import { extractSmartLinkEmbed } from '@atlaskit/link-extractors';
import { fg } from '@atlaskit/platform-feature-flags';
import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
import { expValEqualsNoExposure } from '@atlaskit/tmp-editor-statsig/exp-val-equals-no-exposure';
import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
import { useAnalyticsEvents } from '../../common/analytics/generated/use-analytics-events';
import { CardDisplay } from '../../constants';
import { useSmartLink } from '../../state';
import { succeedUfoExperience } from '../../state/analytics';
import { getClickUrl, getDefinitionId, getExtensionKey, getFirstPartyIdentifier, getObjectAri, getObjectIconUrl, getObjectName, getResourceType, getServices, getThirdPartyARI, isFinalState } from '../../state/helpers';
import { useSmartLinkCrossProductUrlWrapperGated } from '../../state/hooks/use-smart-link-cross-product-url-wrapper';
import { SmartLinkModalProvider } from '../../state/modal';
import { isSpecialClick, isSpecialEvent, isSpecialKey } from '../../utils';
import { combineActionOptions } from '../../utils/actions/combine-action-options';
import { fireLinkClickedEvent } from '../../utils/analytics/click';
import { SmartLinkAnalyticsContext } from '../../utils/analytics/SmartLinkAnalyticsContext';
import { getAnchorAttributesFromEvent, isAuxClick, updateAnchorHref } from '../../utils/click-helpers';
import { isFlexibleUiCard } from '../../utils/flexible';
import * as measure from '../../utils/performance';
import { BlockCard } from '../BlockCard';
import { EmbedCard } from '../EmbedCard';
import FlexibleCard from '../FlexibleCard';
import { InlineCard } from '../InlineCard';
import { useFire3PWorkflowsClickEvent } from '../SmartLinkEvents/useSmartLinkEvents';
import withCardIntersectionObserver from './card-intersection-observer';
import useExperimentMetaEventAttributes from './experiment-meta-event-attributes';
const thirdPartyARIPrefix = 'ari:third-party';
const TRACK_NON_PRIMARY_3P_CLICKS_EXPERIMENT = 'linking_platform_track_non_primary_3p_clicks';
function Component({
  id,
  url,
  title,
  isSelected,
  isHovered,
  frameStyle,
  platform,
  onClick,
  appearance,
  onResolve,
  onError,
  testId,
  actionOptions: actionOptionsProp,
  inheritDimensions,
  embedIframeRef,
  embedIframeUrlType,
  inlinePreloaderStyle,
  ui,
  children,
  showHoverPreview,
  hoverPreviewOptions,
  removeTextHighlightingFromTitle,
  resolvingPlaceholder,
  truncateInline,
  CompetitorPrompt,
  hideIconLoadingSkeleton,
  disablePreviewPanel,
  placeholderData
}) {
  const {
    createAnalyticsEvent
  } = useAnalyticsEventsNext();
  const {
    fireEvent
  } = useAnalyticsEvents();
  let isFlexibleUi = useMemo(() => isFlexibleUiCard(children, ui), [children, ui]);

  // Get state, actions for this card.
  // appearance is pre-resolved by the caller (loader.tsx for Card, ssr.tsx for CardSSR):
  // FlexibleCards are always passed appearance='block' when FG is on, so component.tsx
  // simply consumes whatever appearance it receives.
  const {
    state,
    actions,
    config,
    renderers,
    error,
    isPreviewPanelAvailable,
    openPreviewPanel
  } = useSmartLink(id, url, appearance);
  const ari = getObjectAri(state.details);
  const name = getObjectName(state.details);
  const definitionId = getDefinitionId(state.details);
  const extensionKey = getExtensionKey(state.details);
  const resourceType = getResourceType(state.details);
  const services = getServices(state.details);
  const thirdPartyARI = getThirdPartyARI(state.details);
  const firstPartyIdentifier = getFirstPartyIdentifier();
  const appendCrossProductAnalyticsParams = useSmartLinkCrossProductUrlWrapperGated({
    details: state.details
  });
  const actionOptions = combineActionOptions({
    actionOptions: actionOptionsProp,
    platform
  });

  // TODO: [ZS] Add new experiment flag to determine if the Rovo Actions CTA should be shown
  const rovoActionsCtaShown = false;
  const fire3PClickEvent = fg('platform_smartlink_3pclick_analytics') ?
  // eslint-disable-next-line react-hooks/rules-of-hooks
  useFire3PWorkflowsClickEvent(firstPartyIdentifier, thirdPartyARI) : undefined;

  // Shared scope guard for all 3P-click handlers.
  const shouldFire3PClickEvent = thirdPartyARI && thirdPartyARI.startsWith(thirdPartyARIPrefix) && getClickUrl(url, state.details) === url && fire3PClickEvent && fg('platform_smartlink_3pclick_analytics');
  const getDestinationUrl = useCallback(() => {
    var _getClickUrl, _appendCrossProductAn;
    // FIXME: destinationUrl should be rendered in the DOM anchor href instead of derived at click time
    const preferredUrl = (_getClickUrl = getClickUrl(url, state.details)) !== null && _getClickUrl !== void 0 ? _getClickUrl : url;
    return (_appendCrossProductAn = appendCrossProductAnalyticsParams(preferredUrl)) !== null && _appendCrossProductAn !== void 0 ? _appendCrossProductAn : preferredUrl;
  }, [appendCrossProductAnalyticsParams, state.details, url]);

  // Setup UI handlers.
  const handleClickWrapper = useCallback(event => {
    const isModifierKeyPressed = isSpecialKey(event) || isSpecialClick(event);
    fireEvent('ui.smartLink.clicked', {
      id,
      display: isFlexibleUi ? CardDisplay.Flexible : appearance,
      definitionId: definitionId !== null && definitionId !== void 0 ? definitionId : null,
      isModifierKeyPressed
    });
    if (shouldFire3PClickEvent) {
      // For questions or concerns about this event,
      // please reach out to the 3P Workflows Team via Slack in #help-3p-connector-workflow
      fire3PClickEvent === null || fire3PClickEvent === void 0 ? void 0 : fire3PClickEvent();
    }
    const isDisablePreviewPanel = disablePreviewPanel && editorExperiment('platform_editor_preview_panel_linking_exp', true, {
      exposure: true
    });
    if (fg('platform_smartlink_xpc_url_wrapping')) {
      // FIXME: InlineCard, BlockCard and EmbedCard call event.preventDefault() internally
      // before the event bubbles up to this handler. This forces us to snapshot
      // event.defaultPrevented before calling onClick to detect whether the consumer
      // specifically prevented navigation. Ideally those components should not call
      // preventDefault so this workaround can be removed.
      const isEventDefaultPrevented = event.defaultPrevented;
      const canOpenPreviewPanel = !isModifierKeyPressed && ari && name && openPreviewPanel && (isPreviewPanelAvailable === null || isPreviewPanelAvailable === void 0 ? void 0 : isPreviewPanelAvailable({
        ari
      })) && !isDisablePreviewPanel;

      // Preview panel takes priority over link navigation when available.
      if (canOpenPreviewPanel) {
        var _extractSmartLinkEmbe;
        event.preventDefault();
        event.stopPropagation();
        openPreviewPanel({
          url,
          ari,
          name,
          iconUrl: getObjectIconUrl(state.details),
          panelData: {
            embedUrl: expValEquals('platform_hover_card_preview_panel', 'cohort', 'test') ? (_extractSmartLinkEmbe = extractSmartLinkEmbed(state.details)) === null || _extractSmartLinkEmbe === void 0 ? void 0 : _extractSmartLinkEmbe.src : undefined
          }
        });
        fireLinkClickedEvent(createAnalyticsEvent)(event, {
          attributes: {
            clickOutcome: 'previewPanel'
          }
        });
        return;
      }
      const destinationUrl = getDestinationUrl();
      updateAnchorHref(event, destinationUrl);

      // For FlexibleCard, read target from the clicked anchor element (e.g. _blank for links
      // rendered with explicit target). For classic cards, default to _self
      const {
        target: anchorTarget
      } = getAnchorAttributesFromEvent(event);
      const target = isSpecialEvent(event) ? '_blank' : isFlexibleUi ? anchorTarget : '_self';
      onClick === null || onClick === void 0 ? void 0 : onClick(event, {
        url,
        destinationUrl
      });

      // Check if the event is prevented via onClick callback
      const consumerPreventedNavigation = event.defaultPrevented && !isEventDefaultPrevented;

      // Classic cards (InlineCard, BlockCard, EmbedCard) rely on their own anchor navigation
      // when onClick is provided, so this handler should not open the link for them.
      // FlexibleCard's anchor is prevented from native navigation, so this handler always
      // opens the link for FlexibleCard unless the consumer's onClick called preventDefault.
      const shouldOpenLink = isFlexibleUi || !onClick;
      const doOpenLink = shouldOpenLink && !consumerPreventedNavigation;
      if (doOpenLink) {
        event.preventDefault();
        window.open(destinationUrl, target);
      }

      // Only set clickOutcome when this handler actually opened the link.
      // If a parent onClick handled navigation, fire a generic click event instead.
      fireLinkClickedEvent(createAnalyticsEvent)(event, doOpenLink ? {
        attributes: {
          clickOutcome: target === '_blank' ? 'clickThroughNewTabOrWindow' : 'clickThrough'
        }
      } : undefined);
    } else {
      // If preview panel is available and the user clicked on the link,
      // delegate the click to the preview panel handler
      if (!isModifierKeyPressed && ari && name && openPreviewPanel && isPreviewPanelAvailable !== null && isPreviewPanelAvailable !== void 0 && isPreviewPanelAvailable({
        ari
      }) && !isDisablePreviewPanel) {
        var _extractSmartLinkEmbe2;
        event.preventDefault();
        event.stopPropagation();
        openPreviewPanel({
          url,
          ari,
          name,
          iconUrl: getObjectIconUrl(state.details),
          panelData: {
            embedUrl: expValEquals('platform_hover_card_preview_panel', 'cohort', 'test') ? (_extractSmartLinkEmbe2 = extractSmartLinkEmbed(state.details)) === null || _extractSmartLinkEmbe2 === void 0 ? void 0 : _extractSmartLinkEmbe2.src : undefined
          }
        });
        fireLinkClickedEvent(createAnalyticsEvent)(event, {
          attributes: {
            clickOutcome: 'previewPanel'
          }
        });
        return;
      } else if (!onClick && !isFlexibleUi) {
        const clickUrl = getClickUrl(url, state.details);

        // Ctrl+left click on mac typically doesn't trigger onClick
        // The event could have potentially had `e.preventDefault()` called on it by now
        // event by smart card internally
        // If it has been called then only then can `isSpecialEvent` be true.
        const target = isSpecialEvent(event) ? '_blank' : '_self';
        window.open(clickUrl, target);
        fireLinkClickedEvent(createAnalyticsEvent)(event, {
          attributes: {
            clickOutcome: target === '_blank' ? 'clickThroughNewTabOrWindow' : 'clickThrough'
          }
        });
      } else {
        if (onClick) {
          onClick(event);
        }
        fireLinkClickedEvent(createAnalyticsEvent)(event);
      }
    }
  }, [fireEvent, id, isFlexibleUi, appearance, definitionId, getDestinationUrl, onClick, url, state.details, ari, name, fire3PClickEvent, shouldFire3PClickEvent, isPreviewPanelAvailable, openPreviewPanel, createAnalyticsEvent, disablePreviewPanel]);

  // Exposure fires once per eligible mount; click-time reads use no-exposure variant.
  useEffect(() => {
    if (shouldFire3PClickEvent) {
      expValEquals(TRACK_NON_PRIMARY_3P_CLICKS_EXPERIMENT, 'isEnabled', true);
    }
  }, [shouldFire3PClickEvent]);

  // Middle-click handler to trigger fire3PClickEvent on middle-clicks.
  // Scope is limited to 3P click analytics to keep the experiment focused.
  const handleFrameAuxClick = useCallback(event => {
    if (fg('platform_smartlink_xpc_url_wrapping')) {
      const destinationUrl = getDestinationUrl();
      updateAnchorHref(event, destinationUrl);
    }

    // isAuxClick filters Windows right-clicks (button === 2) that also fire onAuxClick.
    if (isAuxClick(event) && shouldFire3PClickEvent && expValEqualsNoExposure(TRACK_NON_PRIMARY_3P_CLICKS_EXPERIMENT, 'isEnabled', true)) {
      fire3PClickEvent === null || fire3PClickEvent === void 0 ? void 0 : fire3PClickEvent({
        isAuxClick: true
      });
    }
  }, [fire3PClickEvent, getDestinationUrl, shouldFire3PClickEvent]);

  // Right-click handler to trigger fire3PClickEvent on right-clicks.
  // Scope is limited to 3P click analytics to keep the experiment focused.
  const handleFrameContextMenu = useCallback(event => {
    if (fg('platform_smartlink_xpc_url_wrapping')) {
      const destinationUrl = getDestinationUrl();
      updateAnchorHref(event, destinationUrl);
    }
    if (shouldFire3PClickEvent && expValEqualsNoExposure(TRACK_NON_PRIMARY_3P_CLICKS_EXPERIMENT, 'isEnabled', true)) {
      fire3PClickEvent === null || fire3PClickEvent === void 0 ? void 0 : fire3PClickEvent({
        isContextMenu: true
      });
    }
  }, [fire3PClickEvent, getDestinationUrl, shouldFire3PClickEvent]);
  const {
    reload
  } = actions;
  const handleAuthorize = useCallback(() => actions.authorize(appearance), [actions, appearance]);
  const handleRetry = useCallback(() => {
    reload();
  }, [reload]);
  const hasMounted = useRef(false);
  const prevAppearance = useRef(appearance);

  // When appearance changes from inline to non-inline on a mounted card
  // (e.g. direct consumer changes inline → block/embed), reload with the new appearance
  // so ORS can return the appropriate full data. We intentionally do NOT reload on
  // block → embed or embed → block transitions since both already have full ORS data.
  useEffect(() => {
    if (!hasMounted.current) {
      hasMounted.current = true;
      prevAppearance.current = appearance;
      return;
    }
    if (prevAppearance.current === 'inline' && appearance !== 'inline' && fg('platform_smartlink_inline_resolve_optimization')) {
      reload(appearance);
    }
    prevAppearance.current = appearance;
  }, [appearance, reload]);
  const handleInvoke = useCallback(opts => actions.invoke(opts, appearance), [actions, appearance]);
  const experimentMetaEventAttributes = useExperimentMetaEventAttributes({
    actionOptions,
    appearance,
    state
  });

  // NB: for each status change in a Smart Link, a performance mark is created.
  // Measures are sent relative to the first mark, matching what a user sees.
  useEffect(() => {
    measure.mark(id, state.status);
    if (state.status !== 'pending' && state.status !== 'resolving') {
      var _state$error, _state$error2, _state$error3;
      measure.create(id, state.status);
      if (state.status === 'resolved') {
        var _measure$getMeasure$d, _measure$getMeasure;
        fireEvent('operational.smartLink.resolved', {
          definitionId: definitionId !== null && definitionId !== void 0 ? definitionId : null,
          duration: (_measure$getMeasure$d = (_measure$getMeasure = measure.getMeasure(id, state.status)) === null || _measure$getMeasure === void 0 ? void 0 : _measure$getMeasure.duration) !== null && _measure$getMeasure$d !== void 0 ? _measure$getMeasure$d : null
        });
      } else if (((_state$error = state.error) === null || _state$error === void 0 ? void 0 : _state$error.type) !== 'ResolveUnsupportedError' && ((_state$error2 = state.error) === null || _state$error2 === void 0 ? void 0 : _state$error2.type) !== 'UnsupportedError' && ((_state$error3 = state.error) === null || _state$error3 === void 0 ? void 0 : _state$error3.name) !== 'InvalidUrlError') {
        fireEvent('operational.smartLink.unresolved', {
          definitionId: definitionId !== null && definitionId !== void 0 ? definitionId : null,
          reason: state.status,
          error: state.error === undefined ? null : {
            name: state.error.name,
            kind: state.error.kind,
            type: state.error.type
          }
        });
      }
    }
  }, [id, appearance, state.status, state.error, definitionId, extensionKey, resourceType, fireEvent]);

  // NB: once the smart-card has rendered into an end state, we capture
  // this as a successful render. These can be one of:
  // - the resolved state: when metadata is shown;
  // - the unresolved states: viz. forbidden, not_found, unauthorized, errored.
  useEffect(() => {
    if (isFinalState(state.status)) {
      succeedUfoExperience('smart-link-rendered', id || 'NULL', {
        extensionKey,
        display: isFlexibleUi ? 'flexible' : appearance
      });

      // UFO will disregard this if authentication experience has not yet been started
      succeedUfoExperience('smart-link-authenticated', id || 'NULL', {
        display: isFlexibleUi ? 'flexible' : appearance
      });
      fireEvent('ui.smartLink.renderSuccess', {
        display: isFlexibleUi ? 'flexible' : appearance,
        ...(appearance === 'inline' && {
          rovoActionsCtaShown
        }),
        ...(experimentMetaEventAttributes && {
          experimentMeta: experimentMetaEventAttributes
        })
      });
    }
  }, [appearance, extensionKey, fireEvent, id, isFlexibleUi, rovoActionsCtaShown, state.status, experimentMetaEventAttributes]);
  const onIframeDwell = useCallback((dwellTime, dwellPercentVisible) => {
    fireEvent('ui.smartLinkIframe.dwelled', {
      id,
      definitionId: definitionId !== null && definitionId !== void 0 ? definitionId : null,
      display: isFlexibleUi ? 'flexible' : appearance,
      dwellPercentVisible,
      dwellTime
    });
  }, [id, appearance, definitionId, isFlexibleUi, fireEvent]);
  const onIframeFocus = useCallback(() => {
    fireEvent('ui.smartLinkIframe.focused', {
      id,
      definitionId: definitionId !== null && definitionId !== void 0 ? definitionId : null,
      display: isFlexibleUi ? 'flexible' : appearance,
      interactionType: 'focus'
    });
  }, [id, appearance, definitionId, isFlexibleUi, fireEvent]);
  const onIframeMouseEnter = useCallback(() => {
    fireEvent('ui.smartLinkIframe.focused', {
      id,
      definitionId: definitionId !== null && definitionId !== void 0 ? definitionId : null,
      display: isFlexibleUi ? 'flexible' : appearance,
      interactionType: 'mouseenter'
    });
  }, [id, appearance, definitionId, isFlexibleUi, fireEvent]);
  const onIframeMouseLeave = useCallback(() => {
    fireEvent('ui.smartLinkIframe.focused', {
      id,
      definitionId: definitionId !== null && definitionId !== void 0 ? definitionId : null,
      display: isFlexibleUi ? 'flexible' : appearance,
      interactionType: 'mouseleave'
    });
  }, [id, appearance, definitionId, isFlexibleUi, fireEvent]);
  if (isFlexibleUi) {
    let cardState = state;
    if (error) {
      if ((error === null || error === void 0 ? void 0 : error.name) === 'APIError') {
        cardState = {
          status: 'errored'
        };
      } else {
        throw error;
      }
    }
    return /*#__PURE__*/React.createElement(FlexibleCard, {
      id: id,
      cardState: cardState,
      placeholderData: placeholderData,
      onAuthorize: services.length && handleAuthorize || undefined,
      onClick: handleClickWrapper,
      onAuxClick: handleFrameAuxClick,
      onContextMenu: handleFrameContextMenu,
      origin: "smartLinkCard",
      renderers: renderers,
      ui: ui,
      showHoverPreview: showHoverPreview,
      hoverPreviewOptions: hoverPreviewOptions,
      actionOptions: actionOptions,
      url: url,
      title: title,
      testId: testId,
      onResolve: onResolve,
      onError: onError
    }, children);
  }

  // We have to keep this last to prevent hook order from being violated
  if (error) {
    throw error;
  }
  switch (appearance) {
    case 'inline':
      return /*#__PURE__*/React.createElement(InlineCard, {
        id: id,
        url: url,
        renderers: renderers,
        cardState: state,
        handleAuthorize: services.length && handleAuthorize || undefined,
        handleFrameClick: handleClickWrapper,
        handleFrameAuxClick: handleFrameAuxClick,
        handleFrameContextMenu: handleFrameContextMenu,
        isSelected: isSelected,
        isHovered: isHovered,
        onResolve: onResolve,
        onError: onError,
        testId: testId,
        inlinePreloaderStyle: inlinePreloaderStyle,
        showHoverPreview: showHoverPreview,
        hoverPreviewOptions: hoverPreviewOptions,
        actionOptions: actionOptions,
        removeTextHighlightingFromTitle: removeTextHighlightingFromTitle,
        resolvingPlaceholder: resolvingPlaceholder,
        truncateInline: truncateInline,
        hideIconLoadingSkeleton: hideIconLoadingSkeleton
      });
    case 'block':
      return /*#__PURE__*/React.createElement(BlockCard, {
        id: id,
        url: url,
        renderers: renderers,
        authFlow: config && config.authFlow,
        cardState: state,
        handleAuthorize: services.length && handleAuthorize || undefined,
        handleFrameClick: handleClickWrapper,
        handleFrameAuxClick: handleFrameAuxClick,
        handleFrameContextMenu: handleFrameContextMenu,
        isSelected: isSelected,
        onResolve: onResolve,
        onError: onError,
        testId: testId,
        actionOptions: actionOptions,
        CompetitorPrompt: CompetitorPrompt,
        hideIconLoadingSkeleton: hideIconLoadingSkeleton
      });
    case 'embed':
      return /*#__PURE__*/React.createElement(EmbedCard, {
        id: id,
        url: url,
        renderers: renderers,
        cardState: state,
        iframeUrlType: embedIframeUrlType,
        handleAuthorize: services.length && handleAuthorize || undefined,
        handleErrorRetry: handleRetry,
        handleFrameClick: handleClickWrapper,
        handleFrameAuxClick: handleFrameAuxClick,
        handleFrameContextMenu: handleFrameContextMenu,
        handleInvoke: handleInvoke,
        isSelected: isSelected,
        frameStyle: frameStyle,
        platform: platform,
        onResolve: onResolve,
        onError: onError,
        testId: testId,
        inheritDimensions: inheritDimensions,
        actionOptions: actionOptions,
        ref: embedIframeRef,
        onIframeDwell: onIframeDwell,
        onIframeFocus: onIframeFocus,
        onIframeMouseEnter: onIframeMouseEnter,
        onIframeMouseLeave: onIframeMouseLeave,
        CompetitorPrompt: CompetitorPrompt,
        hideIconLoadingSkeleton: hideIconLoadingSkeleton
      });
  }
}
export const CardWithUrlContent = props => {
  const display = isFlexibleUiCard(props.children, props === null || props === void 0 ? void 0 : props.ui) ? CardDisplay.Flexible : props.appearance;
  return /*#__PURE__*/React.createElement(SmartLinkModalProvider, null, /*#__PURE__*/React.createElement(SmartLinkAnalyticsContext, {
    url: props.url,
    id: props.id,
    display: display
  }, /*#__PURE__*/React.createElement(Component, props)));
};
export const CardWithUrl = withCardIntersectionObserver(CardWithUrlContent);