import 'package:better_open_file/better_open_file.dart';
import 'package:bubble/bubble.dart';
import 'package:flowder/flowder.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:jiffy/jiffy.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 '../../../../theming/appTheme.dart';
import '../../../../widget/debug/debugTile.dart';
import '../../files/fileElement.dart';
import 'chatMessage.dart';
import '../messageReactions.dart';

class ChatBubble extends StatefulWidget {
  final BuildContext context;
  final bool isSender;
  final GetChatResponseObject bubbleData;
  final GetRoomResponseObject chatData;

  final void Function({bool renew}) refetch;

  const ChatBubble({
    required this.context,
    required this.isSender,
    required this.bubbleData,
    required this.chatData,
    required this.refetch,
    Key? key}) : super(key: key);

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

class _ChatBubbleState extends State<ChatBubble> {
  BubbleStyle getSystemStyle() {
    return BubbleStyle(
      color: AppTheme.isDarkMode(context) ? const Color(0xff182229) : Colors.white,
      borderWidth: 1,
      elevation: 2,
      margin: const BubbleEdges.only(bottom: 20, top: 10),
      alignment: Alignment.center,
    );
  }

  BubbleStyle getRemoteStyle(bool seamless) {
    var color = AppTheme.isDarkMode(context) ? const Color(0xff202c33) : Colors.white;
    return BubbleStyle(
      nip: BubbleNip.leftTop,
      color: seamless ? Colors.transparent : color,
      borderWidth: seamless ? 0 : 1,
      elevation: seamless ? 0 : 1,
      margin: const BubbleEdges.only(bottom: 10, left: 10, right: 50),
      alignment: Alignment.topLeft,
    );
  }

  BubbleStyle getSelfStyle(bool seamless) {
    var color = AppTheme.isDarkMode(context) ? const Color(0xff005c4b) : const Color(0xffd3d3d3);
    return BubbleStyle(
      nip: BubbleNip.rightBottom,
      color: seamless ? Colors.transparent : color,
      borderWidth: seamless ? 0 : 1,
      elevation: seamless ? 0 : 1,
      margin: const BubbleEdges.only(bottom: 10, right: 10, left: 50),
      alignment: Alignment.topRight,
    );
  }

  late ChatMessage message;
  double downloadProgress = 0;
  Future<DownloaderCore>? downloadCore;

  Size _textSize(String text, TextStyle style) {
    final TextPainter textPainter = TextPainter(
        text: TextSpan(text: text, style: style),
        maxLines: 1,
        textDirection: TextDirection.ltr)
      ..layout(minWidth: 0, maxWidth: double.infinity);
    return textPainter.size;
  }

  BubbleStyle getStyle() {
    if(widget.bubbleData.messageType == GetRoomResponseObjectMessageType.comment) {
      if(widget.isSender) {
        return getSelfStyle(message.containsFile);
      } else {
        return getRemoteStyle(message.containsFile);
      }
    } else {
      return getSystemStyle();
    }
  }


  @override
  Widget build(BuildContext context) {
    message = ChatMessage(originalMessage: widget.bubbleData.message, originalData: widget.bubbleData.messageParameters);
    bool showActorDisplayName = widget.bubbleData.messageType == GetRoomResponseObjectMessageType.comment && widget.chatData.type != GetRoomResponseObjectConversationType.oneToOne;
    bool showBubbleTime = widget.bubbleData.messageType != GetRoomResponseObjectMessageType.system;
    var actorTextStyle = TextStyle(color: Theme.of(context).primaryColor, fontWeight: FontWeight.bold);

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

      children: [
        GestureDetector(
          child: Bubble(

            style: getStyle(),
            child: Container(
              constraints: BoxConstraints(
                maxWidth: MediaQuery.of(context).size.width * 0.9,
                minWidth: showActorDisplayName ? _textSize(widget.bubbleData.actorDisplayName, actorTextStyle).width : 30,
              ),
              child: Stack(
                children: [
                  Padding(
                      padding: EdgeInsets.only(bottom: showBubbleTime ? 18 : 0, top: showActorDisplayName ? 18 : 0),
                      child: message.getWidget()
                  ),
                  Visibility(
                    visible: showActorDisplayName,
                    child: Positioned(
                      top: 0,
                      left: 0,
                      child: Text(
                        widget.bubbleData.actorDisplayName,
                        textAlign: TextAlign.start,
                        style: actorTextStyle,
                      ),
                    ),
                  ),
                  Visibility(
                    visible: showBubbleTime,
                    child: Positioned(
                      bottom: 0,
                      right: 0,
                      child: Text(
                        Jiffy.parseFromMillisecondsSinceEpoch(widget.bubbleData.timestamp * 1000).format(pattern: "HH:mm"),
                        textAlign: TextAlign.end,
                        style: const TextStyle(color: Colors.grey, fontSize: 12),
                      ),
                    ),
                  ),
                  Visibility(
                    visible: downloadProgress > 0,
                    child: Positioned(
                        top: 0,
                        left: 0,
                        right: 0,
                        bottom: 0,
                        child: Stack(
                          children: [
                            const Center(child: Icon(Icons.download)),
                            const Center(child: CircularProgressIndicator(color: Colors.white)),
                            Center(child: CircularProgressIndicator(value: downloadProgress/100)),
                          ],
                        )
                    ),
                  ),
                ],
              ),
            ),
          ),
          onLongPress: () {
            showDialog(context: context, builder: (context) {
              List<String> commonReactions = ["👍", "👎", "😆", "❤️", "👀", "🤔"];
              bool 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)),
                            ),
                          ],
                        ),
                        const Divider(),
                      ],
                    )
                  ),
                  Visibility(
                    visible: canReact,
                    child: ListTile(
                      leading: const Icon(Icons.add_reaction_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: !widget.isSender && widget.chatData.type != GetRoomResponseObjectConversationType.oneToOne,
                    child: ListTile(
                      leading: const Icon(Icons.sms_outlined),
                      title: Text("Private Nachricht an '${widget.bubbleData.actorDisplayName}'"),
                      onTap: () => {},
                    ),
                  ),
                  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()),
                ],
              );
            });
          },
          onTap: () {
            if(message.file == null) return;

            if(downloadProgress > 0) {
              showDialog(context: context, builder: (context) {
                return 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) {
                  return AlertDialog(
                    content: Text(result.message),
                  );
                });
              }
            });
          },
        ),
        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: 5, right: 5),
              child: Wrap(
                alignment: widget.isSender ? WrapAlignment.end : WrapAlignment.start,
                crossAxisAlignment: WrapCrossAlignment.start,
                children: widget.bubbleData.reactions?.entries.map<Widget>((e) {
                  bool 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() ?? [],
              ),
            ),
          ),
        ),
      ],
    );
  }
}