import React, {memo, useCallback, useMemo} from 'react';
import {
  LayoutChangeEvent,
  StyleProp,
  TextStyle,
  TouchableWithoutFeedback,
} from 'react-native';
import {Typography, TypographyProps} from '@components/_core';
import {useAvoidLinkingUrlNavigation} from '@hooks/useAvoidLinkingNavigation';
import {BUBBLE_LONG_PRESS_DELAY, useTapDebounce} from '@hooks/useTapDebounce';
import {BodyAttributes} from '@interfaces/bodyAttributes';
import {HighlightedSpan} from '@modules/chats/interfaces';
import {
  getFullLink,
  getTextSlices,
  openUrlFromApp,
  TextSlice,
  TextSliceType,
} from '@shared/utils';
import {useTheme} from '@shared/theme';

import {styles} from './styles';

const NOOP = () => {};

interface Props extends TypographyProps {
  value: string;
  onTagPress?: (userId: number) => void;
  attributes?: BodyAttributes[];
  highlightedSpans?: HighlightedSpan[];
  searchQuery?: string;
  onNativeLayout?: (e: LayoutChangeEvent) => void;
}

function TypographyWithLinksComponent({
  attributes,
  style,
  onTagPress,
  value,
  highlightedSpans,
  searchQuery,
  onNativeLayout,
  ...props
}: Props) {
  const {onUrlPress} = useAvoidLinkingUrlNavigation();
  const {theme} = useTheme();
  const textSlices = useMemo(
    () =>
      getTextSlices({
        rawContent: value,
        tags: attributes,
        highlightedSpans,
        searchQuery,
      }),
    [value, attributes, highlightedSpans, searchQuery],
  );

  const scheduleTap = useTapDebounce();

  const handleUrlPress = useCallback(
    (link: string) => () => {
      scheduleTap(() => onUrlPress(getFullLink(link)));
    },
    [scheduleTap, onUrlPress],
  );

  const handleTagPress = useCallback(
    (userId?: number) => () => {
      // Avoid handle press for command mentions
      if (!userId || userId < 0) return;
      scheduleTap(() => onTagPress?.(userId));
    },
    [scheduleTap, onTagPress],
  );

  const handleMailPress = useCallback(
    (mail: string) => () => {
      scheduleTap(() => openUrlFromApp(`mailto:${mail}`, false, true));
    },
    [scheduleTap],
  );

  const renderSlice = useCallback(
    (textSlice: TextSlice, index: number) => {
      const typographyProps = {
        ...props,
        color: theme.primary,
        style: [styles.link, style],
        children: textSlice.value,
      };
      switch (textSlice.type) {
        case TextSliceType.TAG:
        case TextSliceType.MENTION:
          return (
            <TouchableWithoutFeedback
              key={index}
              onPress={handleTagPress(textSlice.metadata?.userId)}
              onLongPress={NOOP}
              delayLongPress={BUBBLE_LONG_PRESS_DELAY}
              accessible
              accessibilityRole="link">
              <Typography {...typographyProps} weight={'semiBold'} />
            </TouchableWithoutFeedback>
          );
        case TextSliceType.URL:
          return (
            <TouchableWithoutFeedback
              key={index}
              onPress={handleUrlPress(textSlice.value)}
              onLongPress={NOOP}
              delayLongPress={BUBBLE_LONG_PRESS_DELAY}
              accessible
              accessibilityRole="link">
              <Typography {...typographyProps} />
            </TouchableWithoutFeedback>
          );
        case TextSliceType.MAIL:
          return (
            <TouchableWithoutFeedback
              key={index}
              onPress={handleMailPress(textSlice.value)}
              onLongPress={NOOP}
              delayLongPress={BUBBLE_LONG_PRESS_DELAY}
              accessible
              accessibilityRole="link">
              <Typography {...typographyProps} />
            </TouchableWithoutFeedback>
          );
        case TextSliceType.SEARCH_HIGHLIGHT:
          return (
            <Typography
              key={index}
              {...props}
              style={[
                style,
                {
                  backgroundColor: theme.primary,
                  color: theme.text.neutral.inverted,
                },
              ]}
              accessible
              accessibilityRole="text">
              {textSlice.value}
            </Typography>
          );
        case TextSliceType.TEXT:
        default:
          return `${textSlice.value}`;
      }
    },
    [
      handleTagPress,
      handleUrlPress,
      handleMailPress,
      style,
      theme.primary,
      theme.text.neutral.inverted,
      props,
    ],
  );

  const hiddenTextStyle = useMemo<StyleProp<TextStyle>>(
    () => [
      style,
      {
        position: 'absolute',
        color: 'transparent',
        maxHeight: undefined,
        zIndex: -1,
        opacity: 0,
      },
    ],
    [style],
  );

  const renderText = textSlices.map(renderSlice);

  return (
    <>
      {!!onNativeLayout && (
        <Typography
          onLayout={onNativeLayout}
          style={hiddenTextStyle}
          {...props}>
          {renderText}
        </Typography>
      )}
      <Typography style={style} {...props} accessible={false}>
        {renderText}
      </Typography>
    </>
  );
}

export const TypographyWithLinks = memo(TypographyWithLinksComponent);
