import 'package:better_open_file/better_open_file.dart';
import 'package:bubble/bubble.dart';
import 'package:emoji_picker_flutter/emoji_picker_flutter.dart' as emojis;
import 'package:flowder/flowder.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:jiffy/jiffy.dart';
import '../../../../extensions/text.dart';
import 'package:provider/provider.dart';

import '../../../../api/marianumcloud/talk/chat/getChatResponse.dart';
import '../../../../api/marianumcloud/talk/deleteMessage/deleteMessage.dart';
import '../../../../api/marianumcloud/talk/deleteReactMessage/deleteReactMessage.dart';
import '../../../../api/marianumcloud/talk/deleteReactMessage/deleteReactMessageParams.dart';
import '../../../../api/marianumcloud/talk/reactMessage/reactMessage.dart';
import '../../../../api/marianumcloud/talk/reactMessage/reactMessageParams.dart';
import '../../../../api/marianumcloud/talk/room/getRoomResponse.dart';
import '../../../../model/chatList/chatProps.dart';
import '../../../../widget/debug/debugTile.dart';
import '../../files/fileElement.dart';
import 'answerReference.dart';
import 'chatBubbleStyles.dart';
import 'chatMessage.dart';
import '../messageReactions.dart';

class ChatBubble extends StatefulWidget {
  final BuildContext context;
  final bool isSender;
  final GetChatResponseObject bubbleData;
  final GetRoomResponseObject chatData;
  final bool isRead;
  final String? selfId;

  final double spacing = 3;
  final double timeIconSize = 11;
  final Color timeIconColor = Colors.grey;

  final void Function({bool renew}) refetch;

  const ChatBubble({
    required this.context,
    required this.isSender,
    required this.bubbleData,
    required this.chatData,
    required this.refetch,
    this.isRead = false,
    this.selfId,
    super.key});

  @override
  State<ChatBubble> createState() => _ChatBubbleState();
}

class _ChatBubbleState extends State<ChatBubble> with SingleTickerProviderStateMixin {
  late ChatMessage message;
  double downloadProgress = 0;
  Future<DownloaderCore>? downloadCore;

  late Offset _position = const Offset(0, 0);
  late Offset _dragStartPosition = Offset.zero;

  BubbleStyle getStyle() {
    var styles = ChatBubbleStyles(context);
    if(widget.bubbleData.messageType == GetRoomResponseObjectMessageType.comment) {
      if(widget.isSender) {
        return styles.getSelfStyle(false);
      } else {
        return styles.getRemoteStyle(false);
      }
    } else {
      return styles.getSystemStyle();
    }
  }

  void showOptionsDialog() {
    showDialog(context: context, builder: (context) {
      var commonReactions = <String>['👍', '👎', '😆', '❤️', '👀'];
      var canReact = widget.bubbleData.messageType == GetRoomResponseObjectMessageType.comment;
      return SimpleDialog(
        children: [
          Visibility(
            visible: canReact,
            child: Column(
              mainAxisSize: MainAxisSize.min,
              children: [
                Wrap(
                  alignment: WrapAlignment.center,
                  children: [
                    ...commonReactions.map((e) => TextButton(
                      style: TextButton.styleFrom(
                          padding: EdgeInsets.zero,
                          tapTargetSize: MaterialTapTargetSize.shrinkWrap,
                          minimumSize: const Size(40, 40)
                      ),
                      onPressed: () {
                        Navigator.of(context).pop();
                        ReactMessage(
                          chatToken: widget.chatData.token,
                          messageId: widget.bubbleData.id,
                          params: ReactMessageParams(e),
                        ).run().then((value) => widget.refetch(renew: true));
                      },
                      child: Text(e),
                    ),
                    ),
                    IconButton(
                      onPressed: () {
                        showDialog(context: context, builder: (context) => AlertDialog(
                          contentPadding: const EdgeInsets.all(15),
                          titlePadding: const EdgeInsets.only(left: 6, top: 15),
                          title: Row(
                            mainAxisAlignment: MainAxisAlignment.start,
                            children: [
                              IconButton(
                                onPressed: () {
                                  Navigator.of(context).pop();
                                },
                                icon: const Icon(Icons.arrow_back),
                              ),
                              const SizedBox(width: 10),
                              const Text('Reagieren'),
                            ],
                          ),
                          content: SizedBox(
                            width: 256,
                            height: 270,
                            child: Column(
                              children: [
                                emojis.EmojiPicker(
                                  config: emojis.Config(
                                    height: 256,
                                    swapCategoryAndBottomBar: true,
                                    emojiViewConfig: emojis.EmojiViewConfig(
                                      backgroundColor: Theme.of(context).canvasColor,
                                      recentsLimit: 67,
                                      emojiSizeMax: 25,
                                      noRecents: const Text('Keine zuletzt verwendeten Emojis'),
                                      columns: 7,
                                    ),
                                    bottomActionBarConfig: const emojis.BottomActionBarConfig(
                                      enabled: false,
                                    ),
                                    categoryViewConfig: emojis.CategoryViewConfig(
                                      backgroundColor: Theme.of(context).hoverColor,
                                      iconColorSelected: Theme.of(context).primaryColor,
                                      indicatorColor: Theme.of(context).primaryColor,
                                    ),
                                    searchViewConfig: emojis.SearchViewConfig(
                                      backgroundColor: Theme.of(context).dividerColor,
                                      buttonColor: Theme.of(context).dividerColor,
                                      hintText: 'Suchen',
                                      buttonIconColor: Colors.white,
                                    ),
                                  ),
                                  onEmojiSelected: (emojis.Category? category, emojis.Emoji emoji) {
                                    Navigator.of(context).pop();
                                    Navigator.of(context).pop();
                                    ReactMessage(
                                      chatToken: widget.chatData.token,
                                      messageId: widget.bubbleData.id,
                                      params: ReactMessageParams(emoji.emoji),
                                    ).run().then((value) => widget.refetch(renew: true));
                                  },
                                ),
                              ],
                            ),
                          ),
                        ));
                      },
                      style: IconButton.styleFrom(
                        padding: EdgeInsets.zero,
                        tapTargetSize: MaterialTapTargetSize.shrinkWrap,
                        minimumSize: const Size(40, 40),
                      ),
                      icon: const Icon(Icons.add_circle_outline_outlined),
                    ),
                  ],
                ),
                const Divider(),
              ],
            ),
          ),
          Visibility(
            visible: widget.bubbleData.isReplyable,
            child: ListTile(
              leading: const Icon(Icons.reply_outlined),
              title: const Text('Antworten'),
              onTap: () => {
                Provider.of<ChatProps>(context, listen: false).setReferenceMessageId(widget.bubbleData.id, context, widget.chatData.token),
                Navigator.of(context).pop(),
              },
            ),
          ),
          Visibility(
            visible: canReact,
            child: ListTile(
              leading: const Icon(Icons.emoji_emotions_outlined),
              title: const Text('Reaktionen'),
              onTap: () {
                Navigator.of(context).push(MaterialPageRoute(builder: (context) => MessageReactions(
                  token: widget.chatData.token,
                  messageId: widget.bubbleData.id,
                )));
              },
            ),
          ),
          Visibility(
            visible: !message.containsFile,
            child: ListTile(
              leading: const Icon(Icons.copy),
              title: const Text('Nachricht kopieren'),
              onTap: () => {
                Clipboard.setData(ClipboardData(text: widget.bubbleData.message)),
                Navigator.of(context).pop(),
              },
            ),
          ),
          Visibility(
            visible: !kReleaseMode && !widget.isSender && widget.chatData.type != GetRoomResponseObjectConversationType.oneToOne,
            child: ListTile(
              leading: const Icon(Icons.sms_outlined),
              title: Text("Private Nachricht an '${widget.bubbleData.actorDisplayName}'"),
              onTap: () => {
                Navigator.of(context).pop()
              },
            ),
          ),
          Visibility(
            visible: widget.isSender && DateTime.fromMillisecondsSinceEpoch(widget.bubbleData.timestamp * 1000).add(const Duration(hours: 6)).isAfter(DateTime.now()),
            child: ListTile(
              leading: const Icon(Icons.delete_outline),
              title: const Text('Nachricht löschen'),
              onTap: () {
                DeleteMessage(widget.chatData.token, widget.bubbleData.id).run().then((value) {
                  Provider.of<ChatProps>(context, listen: false).run();
                  Navigator.of(context).pop();
                });
              },
            ),
          ),
          DebugTile(context).jsonData(widget.bubbleData.toJson()),
        ],
      );
    });
  }


  @override
  Widget build(BuildContext context) {
    message = ChatMessage(originalMessage: widget.bubbleData.message, originalData: widget.bubbleData.messageParameters);
    var showActorDisplayName = widget.bubbleData.messageType == GetRoomResponseObjectMessageType.comment && widget.chatData.type != GetRoomResponseObjectConversationType.oneToOne;
    var showBubbleTime = widget.bubbleData.messageType != GetRoomResponseObjectMessageType.system
      && widget.bubbleData.messageType != GetRoomResponseObjectMessageType.deletedComment;

    var parent = widget.bubbleData.parent;
    var actorText = Text(
      widget.bubbleData.actorDisplayName,
      textAlign: TextAlign.start,
      overflow: TextOverflow.ellipsis,
      style: TextStyle(color: Theme.of(context).primaryColor, fontWeight: FontWeight.bold),
    );

    var timeText = Text(
      Jiffy.parseFromMillisecondsSinceEpoch(widget.bubbleData.timestamp * 1000).format(pattern: 'HH:mm'),
      textAlign: TextAlign.end,
      style: TextStyle(color: widget.timeIconColor, fontSize: widget.timeIconSize),
    );

    return Column(
      mainAxisSize: MainAxisSize.min,
      mainAxisAlignment: MainAxisAlignment.end,
      textDirection: TextDirection.ltr,
      crossAxisAlignment: CrossAxisAlignment.end,

      children: [
        GestureDetector(
          onHorizontalDragStart: (details) {
            _dragStartPosition = _position;
          },
          onHorizontalDragUpdate: (details) {
            if(!widget.bubbleData.isReplyable) return;
            var dx = details.delta.dx - _dragStartPosition.dx;
            setState(() {
              _position = (_position.dx + dx).abs() > 30 ? Offset(_position.dx, 0) : Offset(_position.dx + dx, 0);
            });
          },
          onHorizontalDragEnd: (DragEndDetails details) {
            setState(() {
              _position = const Offset(0, 0);
            });
            if(widget.bubbleData.isReplyable) {
              Provider.of<ChatProps>(context, listen: false).setReferenceMessageId(widget.bubbleData.id, context, widget.chatData.token);
            }
          },
          onLongPress: showOptionsDialog,
          onDoubleTap: showOptionsDialog,
          onTap: () {
            if(message.file == null) return;

            if(downloadProgress > 0) {
              showDialog(context: context, builder: (context) => AlertDialog(
                  title: const Text('Download abbrechen?'),
                  content: const Text('Möchtest du den Download abbrechen?'),
                  actions: [
                    TextButton(onPressed: () {
                      Navigator.of(context).pop();
                    }, child: const Text('Nein')),
                    TextButton(onPressed: () {
                      downloadCore?.then((value) {
                        if(!value.isCancelled) value.cancel();
                        Navigator.of(context).pop();
                      });
                      setState(() {
                        downloadProgress = 0;
                        downloadCore = null;
                      });
                    }, child: const Text('Ja, Abbrechen'))
                  ],
                ));

              return;
            }

            downloadProgress = 1;
            downloadCore = FileElement.download(context, message.file!.path!, message.file!.name, (progress) {
              if(progress > 1) {
                setState(() {
                  downloadProgress = progress;
                });
              }
            }, (result) {
              setState(() {
                downloadProgress = 0;
              });

              if(result.type != ResultType.done) {
                showDialog(context: context, builder: (context) => AlertDialog(
                    content: Text(result.message),
                  ));
              }
            });
          },
          child: Transform.translate(
            offset: _position,
            child: Bubble(
              style: getStyle(),
              child: Column(
                children: [
                  Container(
                    constraints: BoxConstraints(
                      maxWidth: MediaQuery.of(context).size.width * 0.9,
                      minWidth: showActorDisplayName
                          ? actorText.size.width
                          : timeText.size.width + (widget.isSender ? widget.spacing + widget.timeIconSize : 0) + 3,
                    ),
                    child: Stack(
                      children: [
                        Visibility(
                          visible: showActorDisplayName,
                          child: Positioned(
                              top: 0,
                              left: 0,
                              child: actorText
                          ),
                        ),
                        Padding(
                          padding: EdgeInsets.only(bottom: showBubbleTime ? 18 : 0, top: showActorDisplayName ? 18 : 0),
                          child: Column(
                            crossAxisAlignment: CrossAxisAlignment.start,
                            children: [
                              if(parent != null && widget.bubbleData.messageType == GetRoomResponseObjectMessageType.comment) ...[
                                AnswerReference(
                                  context: context,
                                  referenceMessage: parent,
                                  selfId: widget.selfId,
                                ),
                                const SizedBox(height: 5),
                              ],
                              message.getWidget(),
                            ],
                          ),
                        ),
                        Visibility(
                          visible: showBubbleTime,
                          child: Positioned(
                              bottom: 0,
                              right: 0,
                              child: Row(
                                children: [
                                  timeText,
                                  if(widget.isSender) ...[
                                    SizedBox(width: widget.spacing),
                                    Icon(
                                        widget.isRead ? Icons.done_all_outlined: Icons.done_outlined,
                                        size: widget.timeIconSize,
                                        color: widget.timeIconColor
                                    )
                                  ]
                                ],
                              )
                          ),
                        ),
                        Visibility(
                          visible: downloadProgress > 0,
                          child: Positioned(
                            bottom: 0,
                            right: 0,
                            left: 0,
                            child: LinearProgressIndicator(value: downloadProgress/100),
                          ),
                        ),
                      ],
                    ),
                  ),
                ],
              ),
            ),
          ),
        ),
        Visibility(
          visible: widget.bubbleData.reactions != null,
          child: Transform.translate(
            offset: const Offset(0, -10),
            child: Container(
              width: MediaQuery.of(context).size.width,
              margin: const EdgeInsets.only(left: 15, right: 15),
              child: Wrap(
                alignment: widget.isSender ? WrapAlignment.end : WrapAlignment.start,
                crossAxisAlignment: WrapCrossAlignment.start,
                children: widget.bubbleData.reactions?.entries.map<Widget>((e) {
                  var hasSelfReacted = widget.bubbleData.reactionsSelf?.contains(e.key) ?? false;
                  return Container(
                    margin: const EdgeInsets.only(right: 2.5, left: 2.5),
                    child: ActionChip(
                      label: Text('${e.key} ${e.value}'),
                      visualDensity: const VisualDensity(vertical: VisualDensity.minimumDensity, horizontal: VisualDensity.minimumDensity),
                      padding: EdgeInsets.zero,
                      backgroundColor: hasSelfReacted ? Theme.of(context).primaryColor : null,
                      onPressed: () {
                        if(hasSelfReacted) {
                          // Delete existing reaction
                          DeleteReactMessage(
                            chatToken: widget.chatData.token,
                            messageId: widget.bubbleData.id,
                            params: DeleteReactMessageParams(e.key),
                          ).run().then((value) => widget.refetch(renew: true));

                        } else {
                          // Add reaction
                          ReactMessage(
                            chatToken: widget.chatData.token,
                            messageId: widget.bubbleData.id,
                            params: ReactMessageParams(e.key)
                          ).run().then((value) => widget.refetch(renew: true));
                        }
                      },
                    ),
                  );
                }).toList() ?? [],
              ),
            ),
          ),
        ),
      ],
    );
  }
}