import React, { useMemo } from 'react';
import {
  I18nManager,
  Image,
  ImageProps,
  Platform,
  StyleSheet,
  Text,
  TextStyle,
  View,
  ViewStyle,
} from 'react-native';

import {
  isFileAttachment,
  isImageAttachment,
  isVideoAttachment,
  MessageComposerState,
} from 'stream-chat';

import { ReplyMessageView } from './ReplyMessageView';

import { useAnnounceOnShow } from '../../a11y/hooks/useAnnounceOnShow';
import { useChatContext } from '../../contexts/chatContext/ChatContext';
import { useComponentsContext } from '../../contexts/componentsContext/ComponentsContext';
import {
  MessageContextValue,
  useMessageContext,
} from '../../contexts/messageContext/MessageContext';
import { useMessageComposer } from '../../contexts/messageInputContext/hooks/useMessageComposer';
import { MessagesContextValue } from '../../contexts/messagesContext/MessagesContext';
import { useTheme } from '../../contexts/themeContext/ThemeContext';
import { useTranslationContext } from '../../contexts/translationContext/TranslationContext';
import { useStateStore } from '../../hooks';
import { primitives } from '../../theme';
import { FileTypes } from '../../types/types';
import { checkQuotedMessageEquality } from '../../utils/utils';
import { FileIcon } from '../Attachment/FileIcon';
import { AttachmentRemoveControl } from '../MessageInput/components/AttachmentPreview/AttachmentRemoveControl';
import { VideoPlayIndicator } from '../ui/VideoPlayIndicator';

const messageComposerStateStoreSelector = (state: MessageComposerState) => ({
  quotedMessage: state.quotedMessage,
});

const ANNOUNCEMENT_TEXT_MAX_LENGTH = 120;

const RightContent = React.memo(
  (props: Pick<ReplyPropsWithContext, 'ImageComponent' | 'message'>) => {
    const { ImageComponent, message } = props;
    const attachments = message?.attachments;
    const styles = useStyles();

    if (!attachments || attachments.length > 1) {
      return null;
    }

    const attachment = attachments?.[0];
    const uri = attachment?.image_url || attachment?.thumb_url;

    if (
      attachment &&
      (isImageAttachment(attachment) ||
        attachment.type === FileTypes.Giphy ||
        attachment.type === FileTypes.Imgur)
    ) {
      return (
        <View style={[styles.contentWrapper, styles.contentBorder]}>
          <ImageComponent source={{ uri }} style={StyleSheet.absoluteFill} />
        </View>
      );
    }
    if (attachment && isVideoAttachment(attachment)) {
      return (
        <View style={[styles.contentWrapper, styles.contentBorder]}>
          <View style={styles.attachmentContainer}>
            <Image source={{ uri: attachment.thumb_url }} style={StyleSheet.absoluteFill} />
            <VideoPlayIndicator size='sm' />
          </View>
        </View>
      );
    }

    if (attachment?.type === FileTypes.VoiceRecording) {
      return null;
    }

    if (attachment && isFileAttachment(attachment)) {
      return <FileIcon mimeType={attachment.mime_type} />;
    }

    return null;
  },
);

export type ReplyPropsWithContext = { ImageComponent: React.ComponentType<ImageProps> } & Pick<
  MessageContextValue,
  'message'
> &
  Pick<MessagesContextValue, 'quotedMessage'> & {
    isMyMessage: boolean;
    isParentMessageMine?: boolean;
    onDismiss?: () => void;
    mode: 'reply' | 'edit';
    // This is temporary for the MessageContent Component to style the Reply component
    styles?: {
      container?: ViewStyle;
      leftContainer?: ViewStyle;
      rightContainer?: ViewStyle;
      title?: TextStyle;
      subtitleContainer?: ViewStyle;
      dismissWrapper?: ViewStyle;
    };
  };

export const ReplyWithContext = (props: ReplyPropsWithContext) => {
  const { t } = useTranslationContext();
  const {
    isMyMessage,
    isParentMessageMine = isMyMessage,
    ImageComponent,
    message: messageFromContext,
    mode,
    onDismiss,
    quotedMessage,
    styles: stylesProp,
  } = props;
  const {
    theme: {
      reply: {
        wrapper,
        container,
        leftContainer,
        rightContainer,
        title: titleStyle,
        dismissWrapper,
      },
    },
  } = useTheme();
  const styles = useStyles({ isMyMessage: isParentMessageMine });

  const title = useMemo(
    () =>
      mode === 'edit'
        ? t('Edit Message')
        : isMyMessage
          ? t('You')
          : quotedMessage?.user?.name
            ? t('Reply to {{name}}', { name: quotedMessage?.user?.name })
            : t('Reply'),
    [mode, isMyMessage, quotedMessage?.user?.name, t],
  );

  if (!quotedMessage) {
    return null;
  }

  return (
    <View
      accessibilityLabel={title}
      accessibilityRole='text'
      style={[!messageFromContext?.quoted_message ? styles.wrapper : null, wrapper]}
    >
      <View style={[styles.container, container, stylesProp?.container]}>
        <View style={[styles.leftContainer, leftContainer, stylesProp?.leftContainer]}>
          <Text numberOfLines={1} style={[styles.title, titleStyle, stylesProp?.title]}>
            {title}
          </Text>

          {/* `isMyMessage` here selects which side to paint, so it takes the surface. */}
          <ReplyMessageView message={quotedMessage} isMyMessage={isParentMessageMine} />
        </View>
        <View style={[styles.rightContainer, rightContainer, stylesProp?.rightContainer]}>
          <RightContent ImageComponent={ImageComponent} message={quotedMessage} />
        </View>
      </View>
      {onDismiss ? (
        <View style={[styles.dismissWrapper, dismissWrapper, stylesProp?.dismissWrapper]}>
          <AttachmentRemoveControl
            accessibilityLabelKey={mode === 'edit' ? 'a11y/Remove edit' : 'a11y/Remove reply'}
            onPress={onDismiss}
          />
        </View>
      ) : null}
    </View>
  );
};

const areEqual = (prevProps: ReplyPropsWithContext, nextProps: ReplyPropsWithContext) => {
  const {
    styles: prevStyles,
    isMyMessage: prevIsMyMessage,
    isParentMessageMine: prevIsParentMessageMine,
    mode: prevMode,
    quotedMessage: prevQuotedMessage,
    onDismiss: prevOnDismiss,
  } = prevProps;
  const {
    styles: nextStyles,
    isMyMessage: nextIsMyMessage,
    isParentMessageMine: nextIsParentMessageMine,
    mode: nextMode,
    quotedMessage: nextQuotedMessage,
    onDismiss: nextOnDismiss,
  } = nextProps;

  if (prevStyles !== nextStyles) {
    return false;
  }

  const isMyMessageEqual = prevIsMyMessage === nextIsMyMessage;

  if (!isMyMessageEqual) {
    return false;
  }

  const isParentMessageMineEqual = prevIsParentMessageMine === nextIsParentMessageMine;

  if (!isParentMessageMineEqual) {
    return false;
  }

  const modeEqual = prevMode === nextMode;
  if (!modeEqual) {
    return false;
  }

  const onDismissEqual = prevOnDismiss === nextOnDismiss;

  if (!onDismissEqual) {
    return false;
  }

  const messageEqual =
    prevQuotedMessage &&
    nextQuotedMessage &&
    checkQuotedMessageEquality(prevQuotedMessage, nextQuotedMessage);

  if (!messageEqual) {
    return false;
  }

  return true;
};

export const MemoizedReply = React.memo(ReplyWithContext, areEqual) as typeof ReplyWithContext;

export type ReplyProps = Partial<ReplyPropsWithContext> &
  Pick<ReplyPropsWithContext, 'mode' | 'onDismiss'>;

/**
 * Mounted only when the Reply is rendered as the composer header preview
 * (edit/reply). Keeps the translation + announcer subscriptions off the
 * per-row in-message quoted-reply render path.
 */
const ReplyComposerAnnouncer = ({
  message,
  mode,
}: {
  message: ReplyPropsWithContext['quotedMessage'];
  mode: ReplyPropsWithContext['mode'];
}) => {
  const { t } = useTranslationContext();
  const truncatedText = useMemo(() => {
    const raw = message?.text?.trim();
    if (!raw) return undefined;
    return raw.length > ANNOUNCEMENT_TEXT_MAX_LENGTH
      ? `${raw.slice(0, ANNOUNCEMENT_TEXT_MAX_LENGTH).trimEnd()}…`
      : raw;
  }, [message?.text]);
  const announcement = useMemo(() => {
    if (mode === 'edit') {
      return truncatedText
        ? t('a11y/Editing message: {{text}}', { text: truncatedText })
        : t('a11y/Editing message');
    }
    const name = message?.user?.name;
    if (!name) return undefined;
    return truncatedText
      ? t('a11y/Replying to {{user}}: {{text}}', { text: truncatedText, user: name })
      : t('a11y/Replying to {{user}}', { user: name });
  }, [mode, message?.user?.name, truncatedText, t]);

  useAnnounceOnShow(true, announcement);
  return null;
};

export const Reply = (props: ReplyProps) => {
  const { isMyMessage: isMyMessageFromContext, message: messageFromContext } = useMessageContext();
  const { client } = useChatContext();
  const { ImageComponent } = useComponentsContext();

  const messageComposer = useMessageComposer();
  const { quotedMessage: quotedMessageFromComposer } = useStateStore(
    messageComposer.state,
    messageComposerStateStoreSelector,
  );

  const quotedMessage = messageFromContext
    ? (messageFromContext.quoted_message as MessagesContextValue['quotedMessage'])
    : quotedMessageFromComposer;

  // `mode='edit'` supplies the edited message via `props.quotedMessage` and leaves
  // the composer's quoted message empty, so ownership must consider both.
  const isMyMessage = client.user?.id === (props.quotedMessage ?? quotedMessage)?.user?.id;
  const isParentMessageMine = messageFromContext ? !!isMyMessageFromContext : undefined;

  // Composer header passes `onDismiss`; the in-message quoted-reply renderer
  // does not. Only the composer-preview path pays for announcement work.
  const isComposerPreview = !!props.onDismiss;

  return (
    <>
      {isComposerPreview ? (
        // Edit passes the message via `quotedMessage` prop; reply uses the
        // composer-state quoted message we computed locally.
        <ReplyComposerAnnouncer message={props.quotedMessage ?? quotedMessage} mode={props.mode} />
      ) : null}
      <MemoizedReply
        ImageComponent={ImageComponent}
        isMyMessage={isMyMessage}
        isParentMessageMine={isParentMessageMine}
        message={messageFromContext}
        quotedMessage={quotedMessage}
        {...props}
      />
    </>
  );
};

const useStyles = ({ isMyMessage = false }: { isMyMessage?: boolean } = {}) => {
  const {
    theme: { semantics },
  } = useTheme();
  const isRTL = I18nManager.isRTL;

  return useMemo(
    () =>
      StyleSheet.create({
        attachmentContainer: {
          alignItems: 'center',
          flex: 1,
          justifyContent: 'center',
        },
        container: {
          borderRadius: primitives.radiusLg,
          flexDirection: isRTL ? 'row-reverse' : 'row',
          padding: primitives.spacingXs,
          backgroundColor: isMyMessage ? semantics.chatBgOutgoing : semantics.chatBgIncoming,
        },
        contentWrapper: {
          borderRadius: primitives.radiusMd,
          borderWidth: 1,
          height: 40,
          overflow: 'hidden',
          width: 40,
        },
        contentBorder: {
          borderColor: semantics.borderCoreOpacitySubtle,
        },
        dismissWrapper: {
          position: 'absolute',
          right: 0,
          top: 0,
        },
        leftContainer: {
          flex: 1,
          justifyContent: 'center',
          paddingHorizontal: primitives.spacingXs,
          gap: primitives.spacingXxxs,
          alignItems: 'flex-start',
          ...(Platform.OS === 'android'
            ? {
                borderLeftColor: isMyMessage
                  ? semantics.chatReplyIndicatorOutgoing
                  : semantics.chatReplyIndicatorIncoming,
                borderLeftWidth: 2,
              }
            : isRTL
              ? {
                  borderRightColor: isMyMessage
                    ? semantics.chatReplyIndicatorOutgoing
                    : semantics.chatReplyIndicatorIncoming,
                  borderRightWidth: 2,
                }
              : {
                  borderLeftColor: isMyMessage
                    ? semantics.chatReplyIndicatorOutgoing
                    : semantics.chatReplyIndicatorIncoming,
                  borderLeftWidth: 2,
                }),
        },
        rightContainer: {},
        title: {
          color: isMyMessage ? semantics.chatTextOutgoing : semantics.chatTextIncoming,
          fontSize: primitives.typographyFontSizeXs,
          fontWeight: primitives.typographyFontWeightSemiBold,
          includeFontPadding: false,
          lineHeight: primitives.typographyLineHeightTight,
          textAlign: isRTL ? 'right' : 'left',
        },
        wrapper: {
          padding: primitives.spacingXxs,
        },
      }),
    [isMyMessage, isRTL, semantics],
  );
};
