content: import 'package:cloud_firestore/cloud_firestore.dart';
  import 'package:flutter/material.dart';
  import 'package:political_think/common/chat/chat_types/flutter_chat_types.dart'
      as types;
  import 'package:political_think/common/components/profile_icon.dart';
  import 'package:political_think/common/constants.dart';
  import 'package:political_think/common/extensions.dart';
  import 'package:visibility_detector/visibility_detector.dart';
  
  import '../../conditional/conditional.dart';
  import '../../models/bubble_rtl_alignment.dart';
  import '../../models/emoji_enlargement_behavior.dart';
  import '../../util.dart';
  import '../state/inherited_chat_theme.dart';
  import '../state/inherited_user.dart';
  import 'file_message.dart';
  import 'image_message.dart';
  import 'message_status.dart';
  import 'text_message.dart';
  import 'user_avatar.dart';
  
  /// Base widget for all message types in the chat. Renders bubbles around
  /// messages and status. Sets maximum width for a message for
  /// a nice look on larger screens.
  class Message extends StatelessWidget {
    /// Creates a particular message from any message type.
    const Message({
      super.key,
      this.audioMessageBuilder,
      this.avatarBuilder,
      this.bubbleBuilder,
      this.bubbleRtlAlignment,
      this.customMessageBuilder,
      this.customStatusBuilder,
      required this.emojiEnlargementBehavior,
      this.fileMessageBuilder,
      required this.hideBackgroundOnEmojiMessages,
      this.imageHeaders,
      this.imageMessageBuilder,
      this.imageProviderBuilder,
      required this.message,
      required this.messageWidth,
      this.nameBuilder,
      this.onAvatarTap,
      this.onMessageDoubleTap,
      this.onMessageLongPress,
      this.onMessageStatusLongPress,
      this.onMessageStatusTap,
      this.onMessageTap,
      this.onMessageVisibilityChanged,
      this.onPreviewDataFetched,
      required this.roundBorder,
      required this.showAvatar,
      required this.showName,
      required this.showStatus,
      required this.showUserAvatars,
      this.textMessageBuilder,
      required this.textMessageOptions,
      required this.usePreviewData,
      this.userAgent,
      this.videoMessageBuilder,
      this.messageExpiryTime,
    });
  
    /// Build an audio message inside predefined bubble.
    final Widget Function(types.AudioMessage, {required int messageWidth})?
        audioMessageBuilder;
  
    /// This is to allow custom user avatar builder
    /// By using this we can fetch newest user info based on id.
    final Widget Function(String userId)? avatarBuilder;
  
    /// Customize the default bubble using this function. `child` is a content
    /// you should render inside your bubble, `message` is a current message
    /// (contains `author` inside) and `nextMessageInGroup` allows you to see
    /// if the message is a part of a group (messages are grouped when written
    /// in quick succession by the same author).
    final Widget Function(
      Widget child, {
      required types.Message message,
      required bool nextMessageInGroup,
    })? bubbleBuilder;
  
    /// Determine the alignment of the bubble for RTL languages. Has no effect
    /// for the LTR languages.
    final BubbleRtlAlignment? bubbleRtlAlignment;
  
    /// Build a custom message inside predefined bubble.
    final Widget Function(types.CustomMessage, {required int messageWidth})?
        customMessageBuilder;
  
    /// Build a custom status widgets.
    final Widget Function(types.Message message, {required BuildContext context})?
        customStatusBuilder;
  
    /// Controls the enlargement behavior of the emojis in the
    /// [types.TextMessage].
    /// Defaults to [EmojiEnlargementBehavior.multi].
    final EmojiEnlargementBehavior emojiEnlargementBehavior;
  
    /// Build a file message inside predefined bubble.
    final Widget Function(types.FileMessage, {required int messageWidth})?
        fileMessageBuilder;
  
    /// Hide background for messages containing only emojis.
    final bool hideBackgroundOnEmojiMessages;
  
    /// See [Chat.imageHeaders].
    final Map<String, String>? imageHeaders;
  
    /// Build an image message inside predefined bubble.
    final Widget Function(types.ImageMessage, {required int messageWidth})?
        imageMessageBuilder;
  
    /// See [Chat.imageProviderBuilder].
    final ImageProvider Function({
      required String uri,
      required Map<String, String>? imageHeaders,
      required Conditional conditional,
    })? imageProviderBuilder;
  
    /// Any message type.
    final types.Message message;
  
    /// Maximum message width.
    final int messageWidth;
  
    /// See [TextMessage.nameBuilder].
    final Widget Function(types.User)? nameBuilder;
  
    /// See [UserAvatar.onAvatarTap].
    final void Function(types.User)? onAvatarTap;
  
    /// Called when user double taps on any message.
    final void Function(BuildContext context, types.Message)? onMessageDoubleTap;
  
    /// Called when user makes a long press on any message.
    final void Function(BuildContext context, types.Message)? onMessageLongPress;
  
    /// Called when user makes a long press on status icon in any message.
    final void Function(BuildContext context, types.Message)?
        onMessageStatusLongPress;
  
    /// Called when user taps on status icon in any message.
    final void Function(BuildContext context, types.Message)? onMessageStatusTap;
  
    /// Called when user taps on any message.
    final void Function(BuildContext context, types.Message)? onMessageTap;
  
    /// Called when the message's visibility changes.
    final void Function(types.Message, bool visible)? onMessageVisibilityChanged;
  
    /// See [TextMessage.onPreviewDataFetched].
    final void Function(types.TextMessage, types.PreviewData)?
        onPreviewDataFetched;
  
    /// Rounds border of the message to visually group messages together.
    final bool roundBorder;
  
    /// Show user avatar for the received message. Useful for a group chat.
    final bool showAvatar;
  
    /// See [TextMessage.showName].
    final bool showName;
  
    /// Show message's status.
    final bool showStatus;
  
    /// Show user avatars for received messages. Useful for a group chat.
    final bool showUserAvatars;
  
    /// Build a text message inside predefined bubble.
    final Widget Function(
      types.TextMessage, {
      required int messageWidth,
      required bool showName,
    })? textMessageBuilder;
  
    /// See [TextMessage.options].
    final TextMessageOptions textMessageOptions;
  
    /// See [TextMessage.usePreviewData].
    final bool usePreviewData;
  
    /// See [TextMessage.userAgent].
    final String? userAgent;
  
    /// Build an audio message inside predefined bubble.
    final Widget Function(types.VideoMessage, {required int messageWidth})?
        videoMessageBuilder;
  
    /// The time at which the message renders the surface color
    /// added to the library for this project
    final int? messageExpiryTime;
  
    Widget _avatarBuilder() => showAvatar
        ? avatarBuilder?.call(message.author.id) ??
            ProfileIcon(radius: IconSize.standard / 2, uid: message.author.id)
        : const SizedBox(width: IconSize.standard);
  
    _getMessageShape(bool currentUserIsAuthor) => BorderRadius.only(
          topLeft: currentUserIsAuthor ? Curvature.standard : Curvature.little,
          topRight: currentUserIsAuthor ? Curvature.little : Curvature.standard,
          bottomLeft: currentUserIsAuthor ? Curvature.standard : Curvature.little,
          bottomRight:
              currentUserIsAuthor ? Curvature.little : Curvature.standard,
        );
  
    Widget _bubbleBuilder(
      BuildContext context,
      BorderRadius borderRadius,
      bool currentUserIsAuthor,
      bool enlargeEmojis,
    ) {
      return Container(
        padding: context.blockPadding,
        constraints: BoxConstraints(
          maxWidth: context.screenSize.width * 0.6,
        ),
        decoration: BoxDecoration(
          color: messageExpiryTime != null &&
                  (message.createdAt ?? 0) > messageExpiryTime!
              // expired
              ? currentUserIsAuthor
                  ? context.surfaceColor
                  : context.primaryColor
              // active
              : message.position?.color ??
                  (currentUserIsAuthor
                      ? context.surfaceColor
                      : context.primaryColor),
          borderRadius: _getMessageShape(currentUserIsAuthor),
        ),
        child: TextMessageText(
          text: (message as types.TextMessage).text,
          bodyTextStyle: TextStyle(
            color: messageExpiryTime != null &&
                    (message.createdAt ?? 0) > messageExpiryTime!
                // expired
                ? currentUserIsAuthor
                    ? context.onSurfaceColor
                    : context.onPrimaryColor
                // active
                : message.position != null
                    ? message.position!.onColor
                    : (currentUserIsAuthor
                        ? context.onSurfaceColor
                        : context.onPrimaryColor),
          ),
        ),
      );
  
      // replaced below with our own builder
  
      // return bubbleBuilder != null
      //     ? bubbleBuilder!(
      //         _messageBuilder(),
      //         message: message,
      //         nextMessageInGroup: roundBorder,
      //       )
      //     : enlargeEmojis && hideBackgroundOnEmojiMessages
      //         ? _messageBuilder()
      //         : Container(
      //             decoration: BoxDecoration(
      //               borderRadius: borderRadius,
      //               color: !currentUserIsAuthor ||
      //                       message.type == types.MessageType.image
      //                   ? InheritedChatTheme.of(context).theme.secondaryColor
      //                   : InheritedChatTheme.of(context).theme.primaryColor,
      //             ),
      //             child: ClipRRect(
      //               borderRadius: borderRadius,
      //               child: _messageBuilder(),
      //             ),
      //           );
    }
  
    Widget _messageBuilder() {
      switch (message.type) {
        case types.MessageType.audio:
          final audioMessage = message as types.AudioMessage;
          return audioMessageBuilder != null
              ? audioMessageBuilder!(audioMessage, messageWidth: messageWidth)
              : const SizedBox();
        case types.MessageType.custom:
          final customMessage = message as types.CustomMessage;
          return customMessageBuilder != null
              ? customMessageBuilder!(customMessage, messageWidth: messageWidth)
              : const SizedBox();
        case types.MessageType.file:
          final fileMessage = message as types.FileMessage;
          return fileMessageBuilder != null
              ? fileMessageBuilder!(fileMessage, messageWidth: messageWidth)
              : FileMessage(message: fileMessage);
        case types.MessageType.image:
          final imageMessage = message as types.ImageMessage;
          return imageMessageBuilder != null
              ? imageMessageBuilder!(imageMessage, messageWidth: messageWidth)
              : ImageMessage(
                  imageHeaders: imageHeaders,
                  imageProviderBuilder: imageProviderBuilder,
                  message: imageMessage,
                  messageWidth: messageWidth,
                );
        case types.MessageType.text:
          final textMessage = message as types.TextMessage;
          return textMessageBuilder != null
              ? textMessageBuilder!(
                  textMessage,
                  messageWidth: messageWidth,
                  showName: showName,
                )
              : TextMessage(
                  emojiEnlargementBehavior: emojiEnlargementBehavior,
                  hideBackgroundOnEmojiMessages: hideBackgroundOnEmojiMessages,
                  message: textMessage,
                  nameBuilder: nameBuilder,
                  onPreviewDataFetched: onPreviewDataFetched,
                  options: textMessageOptions,
                  showName: showName,
                  usePreviewData: usePreviewData,
                  userAgent: userAgent,
                );
        case types.MessageType.video:
          final videoMessage = message as types.VideoMessage;
          return videoMessageBuilder != null
              ? videoMessageBuilder!(videoMessage, messageWidth: messageWidth)
              : const SizedBox();
        default:
          return const SizedBox();
      }
    }
  
    @override
    Widget build(BuildContext context) {
      final query = MediaQuery.of(context);
      final user = InheritedUser.of(context).user;
      final currentUserIsAuthor = user.id == message.author.id;
      final enlargeEmojis =
          emojiEnlargementBehavior != EmojiEnlargementBehavior.never &&
              message is types.TextMessage &&
              isConsistsOfEmojis(
                emojiEnlargementBehavior,
                message as types.TextMessage,
              );
      final messageBorderRadius =
          InheritedChatTheme.of(context).theme.messageBorderRadius;
      final borderRadius = bubbleRtlAlignment == BubbleRtlAlignment.left
          ? BorderRadiusDirectional.only(
              bottomEnd: Radius.circular(
                !currentUserIsAuthor || roundBorder ? messageBorderRadius : 0,
              ),
              bottomStart: Radius.circular(
                currentUserIsAuthor || roundBorder ? messageBorderRadius : 0,
              ),
              topEnd: Radius.circular(messageBorderRadius),
              topStart: Radius.circular(messageBorderRadius),
            )
          : BorderRadius.only(
              bottomLeft: Radius.circular(
                currentUserIsAuthor || roundBorder ? messageBorderRadius : 0,
              ),
              bottomRight: Radius.circular(
                !currentUserIsAuthor || roundBorder ? messageBorderRadius : 0,
              ),
              topLeft: Radius.circular(messageBorderRadius),
              topRight: Radius.circular(messageBorderRadius),
            );
  
      return Container(
        alignment: bubbleRtlAlignment == BubbleRtlAlignment.left
            ? currentUserIsAuthor
                ? AlignmentDirectional.centerEnd
                : AlignmentDirectional.centerStart
            : currentUserIsAuthor
                ? Alignment.centerRight
                : Alignment.centerLeft,
        margin: const EdgeInsets.only(bottom: Margins.quarter),
        child: Row(
          crossAxisAlignment: CrossAxisAlignment.center,
          mainAxisSize: MainAxisSize.min,
          textDirection: bubbleRtlAlignment == BubbleRtlAlignment.left
              ? null
              : TextDirection.ltr,
          children: [
            context.stq,
            if (!currentUserIsAuthor && showUserAvatars) _avatarBuilder(),
            context.sh,
            ConstrainedBox(
              constraints: BoxConstraints(
                maxWidth: messageWidth.toDouble(),
              ),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.end,
                children: [
                  GestureDetector(
                    onDoubleTap: () => onMessageDoubleTap?.call(context, message),
                    onLongPress: () => onMessageLongPress?.call(context, message),
                    onTap: () => onMessageTap?.call(context, message),
                    child: onMessageVisibilityChanged != null
                        ? VisibilityDetector(
                            key: Key(message.id),
                            onVisibilityChanged: (visibilityInfo) =>
                                onMessageVisibilityChanged!(
                              message,
                              visibilityInfo.visibleFraction > 0.1,
                            ),
                            child: _bubbleBuilder(
                              context,
                              borderRadius.resolve(Directionality.of(context)),
                              currentUserIsAuthor,
                              enlargeEmojis,
                            ),
                          )
                        : _bubbleBuilder(
                            context,
                            borderRadius.resolve(Directionality.of(context)),
                            currentUserIsAuthor,
                            enlargeEmojis,
                          ),
                  ),
                ],
              ),
            ),
            context.sh,
            if (currentUserIsAuthor &&
                    MessageStatus.shouldShowMessageStatus(message.status) ||
                !showUserAvatars)
              Padding(
                padding:
                    const EdgeInsets.symmetric(horizontal: IconSize.small / 2),
                child: showStatus
                    ? GestureDetector(
                        onLongPress: () =>
                            onMessageStatusLongPress?.call(context, message),
                        onTap: () => onMessageStatusTap?.call(context, message),
                        child: customStatusBuilder != null
                            ? customStatusBuilder!(message, context: context)
                            : MessageStatus(status: message.status),
                      )
                    : null,
              ),
            if (currentUserIsAuthor &&
                showUserAvatars &&
                !MessageStatus.shouldShowMessageStatus(message.status))
              _avatarBuilder(),
            context.stq,
          ],
        ),
      );
    }
  }
  