import 'dart:async';
import 'dart:io';

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:open_file/open_file.dart';
import 'package:selectable_autolink_text/selectable_autolink_text.dart';
import 'package:telnow_mobile_new/src/api/api_auth_provider.dart';
import 'package:telnow_mobile_new/src/api/jwt_token.dart';
import 'package:telnow_mobile_new/src/layouts/components/template.dart';
import 'package:telnow_mobile_new/src/utils/U.dart';
import 'package:translator/translator.dart';
import 'package:url_launcher/url_launcher.dart';

class MobMessageChatPage extends StatefulWidget {
  final user;
  final String noTicket;
  final String opponent;
  final String messageId;
  final bool askBroadcast;
  final String tenant;
  const MobMessageChatPage(this.user, this.noTicket, this.opponent, this.messageId, this.askBroadcast, this.tenant, {super.key});

  @override
  State<MobMessageChatPage> createState() => _MobMessageChatPageState();
}

class _MobMessageChatPageState extends State<MobMessageChatPage> {
  final ApiAuthProvider apiAuthProvider = ApiAuthProvider();
  final JwtToken token = JwtToken();
  final translator = GoogleTranslator();

  String? idChat;
  String? imagePath;
  String? filePath;
  ScrollController scrollController = ScrollController();
  List messageData = [];

  int page = 0;
  bool isAfterLoad = false;
  String username = '';
  bool isLoad = false;
  bool stopLoad = false;
  bool scrollBottom = false;
  bool isReverse = false;

  @override
  void initState() {
    if(U.getInternetStatus()){
      getData();
      setReadStatus();
      scrollController.addListener(() => scrollListener());
    }
    super.initState();
  }

  setReadStatus() async {
    if (!widget.askBroadcast) {
      await apiAuthProvider.patchData('/api/messages/' + widget.messageId, {'readStatus': 'READ'});
    }
  }

  getData() async {
    idChat = widget.noTicket;
    if (!kIsWeb) {
      imagePath = await token.getPath() + '/TelNow/Images/';
      filePath = await token.getPath() + '/TelNow/Files/';
    }
    username = widget.user['userId'];
    getMessage();
    getCollectionData();
  }

  getMessage() async {
    String url = 'myMessages/$idChat';
    String filter = '{"f":["uniqueId","LIKE","%-%"]}';
    if (widget.askBroadcast) {
      url = 'myBroadcast';
      filter = '{"f":["1","EQ","1"]}';
    }
    if (!isLoad && !stopLoad) {
      setState(() => isLoad = true);
      var mymess = await apiAuthProvider.getData('/api/messages/search/$url', {'isPaged': 'true', 'page': page.toString(), 'size': '20', 'filter': filter, 'tenant': widget.tenant});
      if (mymess.containsKey('_embedded') && mounted) {
        List data = mymess['_embedded']['myMessages'];
        for (int i = 0; i < data.length; i++) {
          if (username == data[i]['from']['user']) {
            data[i]['selected'] = false;
          }
          else{
            if(U.autoTranslate()){
              data[i]['translate'] = '';
            }
          }

          setState(() => messageData.insert(0, data[i]));
          downloadImage(data[i]);
        }
        setState(() {
          if (page == 0) {
            scrollBottom = true;
          }
          isLoad = false;
          page++;

          if (messageData.length >= mymess['page']['totalElements']) {
            stopLoad = true;
          }
        });

        if(U.autoTranslate()){
          translateMessage();
        }
      } else {
        setState(() {
          isLoad = false;
          stopLoad = true;
        });
      }
    }
  }

  translateMessage(){
    var locale = context.locale.toString() == 'zh' ? 'zh-cn' : context.locale.toString();
    messageData.forEach((element) async{
      if (username != element['from']['user'] && element['translate'] == '') {
        var translate = await translator.translate(element['msg']??'', to: locale);
        setState(() {
          element['translate'] = translate.text;
        });
      }
    });
  }

  getCollectionData() {
    FirebaseFirestore.instance.collection("tmMessages").doc('messages').collection(idChat!).snapshots().listen((querySnapshot) {
      setState(() {
        querySnapshot.docChanges.forEach((result) async {
          var data = result.doc.data();
          if (result.type == DocumentChangeType.added && isAfterLoad) {
            if ((username == data!['from']['user'] && messageData.where((element) => element['uniqueId'] == data['uniqueId']).length > 0) || (username != data['from']['user'] && data['readStatus'] == 'DELETED')) {
              int index = messageData.indexWhere((element) => element['uniqueId'] == data['uniqueId']);
              messageData[index]['read'] = data['read'];
              messageData[index]['readStatus'] = data['readStatus'];
              messageData[index]['imageUrl'] = data['imageUrl'];
            } else {
              if(U.autoTranslate()){
                var locale = context.locale.toString() == 'zh' ? 'zh-cn' : context.locale.toString();
                var translate = await translator.translate(data['msg']??'', to: locale);
                data['translate'] = translate.text;
              }
              messageData.add(data);
            }

            downloadImage(data);
          } else if (result.type == DocumentChangeType.modified && isAfterLoad) {
            // print("modified");
            if (messageData.where((element) => element['uniqueId'] == data!['uniqueId']).length > 0) {
              int index = messageData.indexWhere((element) => element['uniqueId'] == data!['uniqueId']);
              messageData[index]['read'] = data!['read'];
              messageData[index]['readStatus'] = data['readStatus'];
            }
          } else if (result.type == DocumentChangeType.removed && isAfterLoad) {
            // print("removed");
          }
        });
        isAfterLoad = true;
      });
    });
  }

  Future<bool> cacheImage(String url, BuildContext context) async {
    bool hasNoError = true;
    var output = Completer<bool>();
    precacheImage(
      NetworkImage(url),
      context,
      onError: (e, stackTrace) => hasNoError = false,
    ).then((_) => output.complete(hasNoError));
    return output.future;
  }

  deleteCollection() {
    debugPrint("popped");
    FirebaseFirestore.instance.collection("tmMessages").doc('messages').collection(idChat!).get().then((value) {
      for (DocumentSnapshot ds in value.docs) {
        ds.reference.delete();
      }
    });
  }

  getImageName(imageUrl) {
    var imgSplit = imageUrl.toString().split('/');
    return imgSplit[imgSplit.length - 1];
  }

  scrollToBottom() {
    scrollController.animateTo(scrollController.position.minScrollExtent, duration: Duration(milliseconds: 1), curve: Curves.decelerate);
    scrollBottom = false;
  }

  scrollListener() {
    if (scrollController.offset >= scrollController.position.maxScrollExtent) {
      // print('loadMessage');
      getMessage();
    }
  }

  downloadImage(data) async {
    if (!kIsWeb && data['imageUrl'] != null && data['imageUrl'] != '') {
      int index = messageData.indexWhere((element) => element['uniqueId'] == data['uniqueId']);
      setState(() => messageData[index]['loadingImage'] = true);

      if (data['imageUrl'].split('.').last == 'pdf') {
        if (!File(filePath! + getImageName(data['imageUrl'])).existsSync()) {
          await apiAuthProvider.downloadImage(data['imageUrl'], filePath! + getImageName(data['imageUrl']));
        }
      } else {
        if (!File(imagePath! + getImageName(data['imageUrl'])).existsSync()) {
          if (await cacheImage(data['imageUrl'], context)) {
            await apiAuthProvider.downloadImage(data['imageUrl'], imagePath! + getImageName(data['imageUrl']));
          }
        }
      }

      setState(() => messageData[index]['loadingImage'] = false);
    }
  }

  @override
  Widget build(BuildContext context) {
    var bodyWidth = U.bodyWidth(context);
    WidgetsBinding.instance.addPostFrameCallback((_) {
      if (messageData.isNotEmpty) {
        if (scrollController.position.maxScrollExtent > 0 && !isReverse) {
          setState(() => isReverse = true);
        }

        if (isAfterLoad && scrollBottom && isReverse) {
          scrollToBottom();
        }
      }
    });

    return PopScope(
      onPopInvoked: (didPop) async {
        deleteCollection();
        Navigator.of(context).pop();
        // return true;
      },
      child: Scaffold(
        backgroundColor: Colors.white,
        resizeToAvoidBottomInset: true,
        appBar: appBarTemplate(context: context, title: widget.opponent != 'all_informants' ? widget.opponent : "allInformants".tr()),
        body: Column(
          children: [
            divider(),
            U.getInternetStatus()?Expanded(
              child: SizedBox(width: bodyWidth,
                child:LayoutBuilder(
                    builder: (context,constraint) {
                      return messageData.isEmpty && !isAfterLoad ? loadingTemplateNoVoid() : Column(
                        children: [
                          Expanded(
                            child: SingleChildScrollView(
                              padding: const EdgeInsets.fromLTRB(10, 10, 10, 7),
                              controller: scrollController,
                              reverse: isReverse,
                              child: Column(
                                children: List.generate(messageData.length, (i) {
                                  bool hideDate = i == 0 ? false : checkDate(messageData[i]['datetime'], messageData[i - 1]['datetime']);
                                  bool isNip = i == 0 ? true : !hideDate ? true : messageData[i]['from']['user'] == messageData[i - 1]['from']['user'] ? false : true;
                                  return Column(
                                    children: [
                                      !hideDate ? Center(
                                        child: Padding(
                                          padding: const EdgeInsets.all(10),
                                          child: bubble_chat(Text(convertDate(messageData[i]['datetime'], context.locale.toString()), textAlign: TextAlign.center, style: TextStyle(fontSize: 12)), null, false, false),
                                        ),
                                      ) : Container(),
                                      Builder(builder: (context) {
                                        var isMe = messageData[i]['from']['user'] == widget.user['userId'];
                                        var isFile = messageData[i]['imageUrl'] != null && messageData[i]['imageUrl'] != '' && messageData[i]['readStatus'] != 'DELETED';
                                        var isPdf = isFile && messageData[i]['imageUrl'].split('.').last == 'pdf';
                                        var isImg = isFile && !isPdf;
                                        var isTranslate = U.autoTranslate() && !isMe && messageData[i]['msg'] != messageData[i]['translate'];

                                        var wdg = messageData[i]['readStatus'] == 'DELETED' ? Text('deletedMessage'.tr(), style: TextStyle(fontSize: 14, color: Colors.black54, fontStyle: FontStyle.italic)) : Column(
                                          crossAxisAlignment: CrossAxisAlignment.start,
                                          children: [
                                            isPdf ? GestureDetector(
                                              child: Builder(builder: (context) {
                                                var pdfContainer = Container(
                                                  padding: EdgeInsets.all(6),
                                                  decoration: BoxDecoration(color: Colors.black12.withValues(alpha: 0.1), borderRadius: BorderRadius.all(Radius.circular(4))),
                                                  child: Row(
                                                    mainAxisSize: MainAxisSize.min,
                                                    children: [
                                                      Icon(Icons.picture_as_pdf),
                                                      SizedBox(
                                                        width: 6,
                                                      ),
                                                      Flexible(child: Text(getImageName(messageData[i]['imageUrl'])))
                                                    ],
                                                  ),
                                                );

                                                if (kIsWeb) {
                                                  return pdfContainer;
                                                } else if (File(filePath! + getImageName(messageData[i]['imageUrl'])).existsSync()) {
                                                  return pdfContainer;
                                                } else {
                                                  return NoImageFound(messageData[i]['loadingImage'] ? false : true);
                                                }
                                              }),
                                              onTap: () async {
                                                kIsWeb ? await launchUrl( messageData[i]['imageUrl']) : File(filePath! + getImageName(messageData[i]['imageUrl'])).existsSync() ? await OpenFile.open(filePath! + getImageName(messageData[i]['imageUrl'])) : null;
                                              },
                                            ) : isImg ? GestureDetector(
                                              child: Container(
                                                  margin: const EdgeInsets.only(bottom: 5),
                                                  child: Builder(builder: (context) {
                                                    if (kIsWeb) {
                                                      return Image.network(messageData[i]['imageUrl'], fit: BoxFit.cover, width: 200, height: 200);
                                                    } else if (File(imagePath! + getImageName(messageData[i]['imageUrl'])).existsSync()) {
                                                      return Image.file(File(imagePath! + getImageName(messageData[i]['imageUrl'])), fit: BoxFit.cover, width: 200, height: 200);
                                                    } else {
                                                      return NoImageFound(messageData[i]['loadingImage'] ? false : true);
                                                    }
                                                  })
                                              ),
                                              onTap: () => kIsWeb ? navigateTo(context, PhotoPreview(widget.opponent, messageData[i]['imageUrl'], true)) : File(imagePath! + getImageName(messageData[i]['imageUrl'])).existsSync() ? navigateTo(context, PhotoPreview(widget.opponent, File(imagePath! + getImageName(messageData[i]['imageUrl'])), false)) : null,
                                            ) : SizedBox(height: 1),
                                            messageData[i]['msg'] != null && messageData[i]['msg'] != '' ? Column(
                                              crossAxisAlignment: !isMe?CrossAxisAlignment.start:CrossAxisAlignment.end,
                                              children: [
                                                SizedBox(height: 4),
                                                SelectableAutoLinkText(
                                                  messageData[i]['msg'],
                                                  style: TextStyle(fontSize: 14, color: Colors.black),
                                                  linkStyle: TextStyle(color: Colors.blueAccent),
                                                  highlightedLinkStyle: TextStyle(color: Colors.blueAccent, backgroundColor: Colors.blueAccent.withAlpha(0x33)),
                                                  onTap: (link) async{
                                                    if (await canLaunchUrl(Uri.parse(link))) {
                                                      await launchUrl(Uri.parse(link));
                                                    }
                                                  },
                                                  onLongPress: (link) {
                                                    Clipboard.setData(new ClipboardData(text: link)).then((value){
                                                      showSuccess('link_copied'.tr(), context);
                                                    });
                                                  },
                                                  enableInteractiveSelection: false,
                                                ),
                                                isTranslate ? Container(
                                                  margin: EdgeInsets.only(top: 2), decoration: BoxDecoration(border: Border(top: BorderSide(color: Colors.black.withValues(alpha: 0.2)))),
                                                  child: Text(messageData[i]['translate']!=''?'(${messageData[i]['translate']})':'...', style: TextStyle(fontSize: 14, color: Colors.black.withValues(alpha: 0.65), fontStyle: FontStyle.italic)),
                                                ) : Container(),
                                              ],
                                            )
                                                : Container()
                                          ],
                                        );

                                        var timeBubble = Positioned(
                                          bottom: 0,
                                          right: isNip ? 6 : 0,
                                          child: Text(DateFormat('HH:mm').format(DateTime.parse(messageData[i]['datetime'])),
                                              style: TextStyle(fontSize: 10, color: Colors.black45)),
                                        );

                                        var expander = Expanded(
                                            flex: 8,
                                            child: Column(
                                              children: [
                                                bubble_chat(wdg, timeBubble, isNip, isMe),
                                                SizedBox(
                                                  height: 5,
                                                ),
                                              ],
                                              crossAxisAlignment: isMe ? CrossAxisAlignment.end : CrossAxisAlignment.start,
                                            ));

                                        return isMe
                                            ? Row(
                                          children: [
                                            Expanded(
                                              flex: 2,
                                              child: Container(),
                                            ),
                                            expander,
                                          ],
                                        )
                                            : Row(
                                          children: [
                                            expander,
                                            Expanded(
                                              flex: 2,
                                              child: Container(),
                                            ),
                                          ],
                                        );
                                      }),
                                    ],
                                  );
                                }),
                              ),
                            ),
                          ),
                        ],
                      );
                    }
                ),
              ),
            ):Container(
              margin: EdgeInsets.all(20),
              child: Text('noInternetDesc'.tr(), style: TextStyle(color: textColor.withValues(alpha: 0.65), fontStyle: FontStyle.italic, height: 1.5, fontSize: 16.0), textAlign: TextAlign.center),
            )
          ],
        ),
      ),
    );
  }

  Widget bubble_chat(Widget child, Widget? time, bool isNip, bool isMe) {
    bool isDate = false;
    if (time == null) {
      isDate = true;
      time = Container();
    }
    Color color = isMe ? primaryColor.withValues(alpha: 0.3) : isDate ? Color(0xffD5F5FF) : Color(0xffECECEC);
    var clipPath = ClipPath(
      child: ConstrainedBox(
        constraints: BoxConstraints(minWidth: 50),
        child: Container(
          decoration: BoxDecoration(
            color: color,
          ),
          child: Padding(padding: EdgeInsets.all(8),
            child: isDate ? child : Stack(
              children: [
                Padding(
                  padding: EdgeInsets.only(
                    bottom: 15,
                    right: isNip && isMe ? 6 : 0,
                    left: isNip && !isMe ? 6 : 0,
                  ),
                  child: child,
                ),
                time
              ],
            ),
          ),
        ),
      ),
      clipper: isMe ? MyClipper(isNip) : YourClipper(isNip),
    );

    return Padding(
        padding: EdgeInsets.only(
            right: isNip && isMe ? 0 : 6,
            left: isNip && !isMe ? 0 : 6
        ),
        child: clipPath
    );
  }

  bool checkDate(date1, date2) {
    final dateToCheck1 = DateTime(DateTime.parse(date1).year, DateTime.parse(date1).month, DateTime.parse(date1).day);
    final dateToCheck2 = DateTime(DateTime.parse(date2).year, DateTime.parse(date2).month, DateTime.parse(date2).day);

    return dateToCheck1 == dateToCheck2 ? true : false;
  }

  String convertDate(date, locale) {
    final dateToCheck = DateTime.parse(date);

    final now = DateTime.now();
    final today = DateTime(now.year, now.month, now.day);
    final yesterday = DateTime(now.year, now.month, now.day - 1);

    final aDate = DateTime(dateToCheck.year, dateToCheck.month, dateToCheck.day);
    if (aDate == today) {
      return 'today'.tr();
    } else if (aDate == yesterday) {
      return 'yesterday'.tr();
    } else {
      return DateFormat('dd MMMM yyyy', locale).format(DateTime.parse(date));
    }
  }
}
