/// 聊天模板
library;

import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:loopin/IM/controller/chat_controller.dart';
import 'package:loopin/IM/controller/chat_detail_controller.dart';
import 'package:loopin/IM/im_message.dart';
import 'package:loopin/IM/im_result.dart';
import 'package:loopin/IM/im_service.dart';
import 'package:loopin/components/image_viewer.dart';
import 'package:loopin/components/network_or_asset_image.dart';
import 'package:loopin/components/preview_video.dart';
import 'package:loopin/models/conversation_type.dart';
import 'package:loopin/models/summary_type.dart';
import 'package:loopin/pages/chat/notify_controller/notify_no_friend_controller.dart';
import 'package:loopin/utils/audio_player_service.dart';
import 'package:loopin/utils/snapshot.dart';
import 'package:shirne_dialog/shirne_dialog.dart';
import 'package:tencent_cloud_chat_sdk/models/v2_tim_conversation.dart';
import 'package:tencent_cloud_chat_sdk/models/v2_tim_message.dart';
import 'package:wechat_assets_picker/wechat_assets_picker.dart';

import '../../styles/index.dart';
import '../../utils/index.dart';
import './components/redpacket.dart';
import './components/richtext.dart';
// import 'mock/chat_json.dart';
import 'mock/emoj_json.dart';

class ChatNoFriend extends StatefulWidget {
  const ChatNoFriend({super.key});

  @override
  State<ChatNoFriend> createState() => _ChatNoFriendState();
}

class _ChatNoFriendState extends State<ChatNoFriend> with SingleTickerProviderStateMixin {
  late final ChatDetailController controller;
  // 接收参数
  late final Rx<V2TimConversation> arguments;

  late String selfUserId;

  // 聊天消息模块
  final bool isNeedScrollBottom = true;

  final String _tips = '回复或关注对方之前,对方只能发送一条消息';

  bool isLoading = false; // 是否在加载中
  bool hasMore = true; // 是否还有更多数据
  final RxBool _throttleFlag = false.obs; // 滚动节流锁

  RxMap<String, bool> voicePlayingMap = <String, bool>{}.obs;

  // 表情json
  List emoJson = emotionData;

  // 底部操作栏模块
  TextEditingController editorController = TextEditingController();
  FocusNode editorFocusNode = FocusNode();
  bool voiceBtnEnable = false; // 语音按钮
  bool voicePanelEnable = false; // 语音操作面板
  bool voiceToTransfer = false; // 语音转文字中
  int voiceType = 0; // 语音操作类型
  Map voiceTypeMap = {
    0: '按住 说话', // 按住说话
    1: '松开 发送', // 松开发送
    2: '松开 取消', // 松开取消(左滑)
    3: '语音转文字', // 语音转文字(右滑)
  };
  bool toolbarEnable = false; // 显示表情/选择区域
  int toolbarIndex = 0; // 0 表情 1 选择
  double keyboardHeight = 157.6; // 键盘高度
  List chooseOptions = [
    {'key': 'photo', 'name': '相册', 'icon': 'assets/images/icon_photo.webp'},
    {'key': 'camera', 'name': '拍摄', 'icon': 'assets/images/icon_camera.webp'},
    // {'key': 'location', 'name': '位置', 'icon': 'assets/images/icon_location.webp'},
    {'key': 'redpacket', 'name': '红包', 'icon': 'assets/images/icon_hb.webp'},
  ];

  // controller监听
  // ScrollController chatController = ScrollController();
  late ScrollController chatController;

  ScrollController emojController = ScrollController();

  // 模拟开红包按钮动画
  late AnimationController animController;

  // 创建一个从 0 到 π 的旋转动画
  late Animation<double> animTurns;

  // 初始化状态
  @override
  void initState() {
    super.initState();
    final arg = Get.arguments as V2TimConversation;
    arguments = arg.obs;
    controller = Get.find<ChatDetailController>();
    chatController = controller.chatController;

    animController = AnimationController(
      vsync: this,
      duration: Duration(milliseconds: 500),
    );
    animTurns = Tween<double>(begin: 0, end: 3.1415926).animate(animController);

    cleanUnRead();

    getUserId();

    isMyFriend();

    getMsgData(initFlag: true);

    // 编辑框获取焦点
    editorFocusNode.addListener(() {
      if (editorFocusNode.hasFocus) {
        setState(() {
          toolbarEnable = false;
        });
        controller.scrollToBottom();
      }
    });
    // 滚动监听
    // Future.delayed(Duration(milliseconds: 1000), () {

    // });
    chatController.addListener(() {
      if (_throttleFlag.value) return;
      if (chatController.position.pixels >= chatController.position.maxScrollExtent - 50) {
        // if (chatController.position.pixels <= 50) {
        _throttleFlag.value = true;
        getMsgData().then((_) {
          // 解锁
          Future.delayed(Duration(milliseconds: 1000), () {
            _throttleFlag.value = false;
          });
        });
      }
    });
  }

  @override
  void dispose() {
    if (Get.isRegistered<ChatDetailController>()) {
      Get.delete<ChatDetailController>();
    }
    emojController.dispose();
    editorFocusNode.dispose();
    animController.dispose();
    super.dispose();
  }

  // 设置好友备注
  void setRemark() async {
    print('不支持');
  }

  void isMyFriend() async {
    final isFriendId = arguments.value.userID;
    // final isfd = await ImService.instance.isMyFriend(isFriendId!, FriendTypeEnum.V2TIM_FRIEND_TYPE_BOTH);
    // if (isfd.success) {
    //   controller.isFriend.value = isfd.data;
    //   print(isfd.data);
    // } else {
    //   controller.isFriend.value = false;
    //   print(isfd.desc);
    // }
    /// 0：不是好友也没有关注
    /// 1：你关注了对方（单向）
    /// 2：对方关注了你（单向）
    /// 3：互相关注（双向好友）
    final isfd = await ImService.instance.checkFollowType(userIDList: [isFriendId!]);
    if (isfd.success) {
      controller.followType.value = isfd.data?.first.followType ?? 0;
      if ([3].contains(controller.followType.value)) {
        controller.isFriend.value = true;
      } else {
        controller.isFriend.value = false;
      }
      logger.i('当前聊天的关系为：${controller.followType.value}');
    }
  }

  bool checkSend() {
    if (controller.isFriend.value) {
      // 是好友直接发
      return true;
    } else {
      // 不是好友
      if (arguments.value.lastMessage != null) {
        // 最后一条消息是否我发的
        // final isSelf = arguments.value.lastMessage!.isSelf;
        final isSelf = controller.chatList.first.isSelf;
        return isSelf == true ? false : true;
      } else {
        return true;
      }
    }
  }

  void cleanUnRead() async {
    if ((arguments.value.unreadCount ?? 0) > 0) {
      final res = await ImService.instance.clearConversationUnreadCount(conversationID: arguments.value.conversationID);

      if (!res.success) {
        MyDialog.toast('清理未读异常：${res.desc}', icon: Icon(Icons.warning), style: ToastStyle(backgroundColor: Colors.red.withAlpha(200)));
      }
      logger.w('清理陌生人会话未读消息,准备刷新消息页的UI，陌生人会话列表的UI');
      // 是否从未读会话列表而来
      if (Get.isRegistered<NotifyNoFriendController>()) {
        final ctl = Get.find<NotifyNoFriendController>();
        ctl.updateUnread(conversationID: arguments.value.conversationID);
      }
    }
  }

  void getUserId() async {
    final idRes = await ImService.instance.selfUserId();
    if (idRes.success) {
      selfUserId = idRes.data;
    }
  }

  Future<void> getMsgData({bool initFlag = false}) async {
    if (isLoading || !hasMore) return; // 正在加载 or 没有更多了

    isLoading = true;

    // 获取最旧一条消息作为游标
    V2TimMessage? lastRealMsg;
    // for (var msg in controller.chatList.reversed) {
    for (var msg in controller.chatList.reversed) {
      if (msg.localCustomData != 'time_label') {
        lastRealMsg = msg;
        break;
      }
    }
    final lastMsg = lastRealMsg ?? arguments.value.lastMessage; // 如果找不到，就用传入的参数
    // print(lastMsg?.toJson());

    // final lastMsg = controller.chatList.isNotEmpty ? controller.chatList.last : arguments.lastMessage;

    final res = await ImService.instance.getHistoryMessageList(
      userID: arguments.value.userID,
      lastMsg: lastMsg,
    );

    if (res.success) {
      final newMessages = res.data ?? [];

      if (newMessages.isEmpty) {
        hasMore = false;
        // MyDialog.toast('没有更多了~', icon: Icon(Icons.warning), style: ToastStyle(backgroundColor: Colors.red.withAlpha(200)));
      }
      if (initFlag && lastMsg != null) {
        newMessages.insert(0, lastMsg);
        // controller.scrollToBottom();
      }
      controller.updateChatListWithTimeLabels(newMessages);
      if (initFlag) {
        // 初始化时滚到最底部
        WidgetsBinding.instance.addPostFrameCallback((_) {
          if (chatController.hasClients) {
            // controller.scrollToBottom();
            // final bottomPadding = MediaQuery.of(context).padding.bottom; // 底部安全区域高度
            // chatController.jumpTo(chatController.position.maxScrollExtent); // 60为底部操作栏高度
            chatController.jumpTo(0);
          }
        });
      }

      print('聊天数据加载成功');
    } else {
      MyDialog.toast("获取聊天记录失败：${res.desc}", icon: Icon(Icons.warning), style: ToastStyle(backgroundColor: Colors.red.withAlpha(200)));
    }

    isLoading = false;
  }

  // 渲染聊天消息
  List<Widget> renderChatList() {
    List<Widget> msgtpl = [];
    for (var item in controller.chatList) {
      // 时间提示，公告提示
      if (item.localCustomData == 'time_label') {
        msgtpl.add(Container(
          margin: const EdgeInsets.only(bottom: 15.0),
          child: Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Text(
                item.customElem!.data ?? '',
                style: TextStyle(color: Colors.grey[600], fontSize: 12.0),
              ),
            ],
          ),
        ));
      }
      // 写入记录的tips
      else if (item.cloudCustomData == 'tips') {
        msgtpl.add(
          Container(
            margin: const EdgeInsets.only(bottom: 15.0),
            width: double.infinity,
            child: Text(
              item.textElem!.text ?? '',
              style: TextStyle(color: Colors.grey[600], fontSize: 12.0),
              softWrap: true,
              maxLines: 5,
              overflow: TextOverflow.ellipsis,
              textAlign: TextAlign.center,
            ),
          ),
        );
      }
      // 文本消息模板=1
      else if (item.elemType == 1 && item.cloudCustomData != 'tips') {
        msgtpl.add(
          RenderChatItem(
            data: item,
            child: Ink(
              decoration: BoxDecoration(
                color: !(item.isSelf ?? false) ? Color(0xFFFFFFFF) : Color(0xFF89E45B),
                borderRadius: BorderRadius.circular(10.0),
              ),
              child: InkWell(
                overlayColor: WidgetStateProperty.all(Colors.transparent),
                borderRadius: BorderRadius.circular(10.0),
                child: Container(
                  padding: const EdgeInsets.all(10.0),
                  child: RichTextUtil.getRichText(item.textElem?.text ?? '', color: !(item.isSelf ?? false) ? Colors.black : Colors.white), // 可自定义解析emoj/网址/电话
                ),
                onLongPress: () {
                  contextMenuDialog();
                },
              ),
            ),
          ),
        );
      }
      // gif表情模板=8
      else if (item.elemType == 8) {
        msgtpl.add(RenderChatItem(
          data: item,
          child: Ink(
            child: InkWell(
              overlayColor: WidgetStateProperty.all(Colors.transparent),
              child: Container(
                constraints: const BoxConstraints(
                  maxHeight: 100.0,
                  maxWidth: 100.0,
                ),
                // child: Image.asset('assets/images/emotion/${item.faceElem?.data}'),
                child: Image.asset('${item.faceElem?.data}'),
              ),
              onLongPress: () {
                contextMenuDialog();
              },
            ),
          ),
        ));
      }
      // 图片模板=3
      else if (item.elemType == 3) {
        // List<String> imagePaths = item.imageElem?.imageList?.where((e) => e != null && e.url != null).map((e) => e!.url!).toList() ?? [];
        final originImage = item.imageElem?.imageList?.firstWhere((e) => e?.type == 0 && e?.url != null, orElse: () => null);
        List<String> imagePaths = originImage != null ? [originImage.url!] : [];
        msgtpl.add(RenderChatItem(
          data: item,
          child: Ink(
            child: InkWell(
              onTap: () {
                // 预览图片
                Get.to(() => ImageViewer(
                      images: [imagePaths.first],
                      index: 0,
                    ));
              },
              overlayColor: WidgetStateProperty.all(Colors.transparent),
              child: ClipRRect(
                borderRadius: BorderRadius.circular(10.0),
                // child: ImageGroup(
                //   images: imagePaths,
                //   width: 120,
                // ),
                child: Image.network(
                  imagePaths.first,
                  width: 120,
                  fit: BoxFit.cover,
                  loadingBuilder: (context, child, loadingProgress) {
                    if (loadingProgress == null) {
                      // controller.scrollToBottom();
                      return child; // 加载完成，显示图片
                    }
                    return Container(
                      width: 120,
                      height: 240,
                      color: Colors.grey[300],
                      alignment: Alignment.center,
                      child: CircularProgressIndicator(
                        value: loadingProgress.expectedTotalBytes != null ? loadingProgress.cumulativeBytesLoaded / loadingProgress.expectedTotalBytes! : null,
                      ),
                    );
                  },
                  errorBuilder: (context, error, stackTrace) {
                    return Container(
                      color: Colors.grey[300],
                      alignment: Alignment.center,
                      child: Icon(Icons.broken_image, color: Colors.grey, size: 40),
                    );
                  },
                ),
              ),
              onLongPress: () {
                contextMenuDialog();
              },
            ),
          ),
        ));
      }
      // 视频模板=5
      else if (item.elemType == 5) {
        // print(item.videoElem!.toLogString());
        msgtpl.add(RenderChatItem(
          data: item,
          child: Ink(
            child: InkWell(
              overlayColor: WidgetStateProperty.all(Colors.transparent),
              child: SizedBox(
                width: 120.0,
                child: Stack(
                  alignment: Alignment.center,
                  children: [
                    ClipRRect(
                      borderRadius: BorderRadius.circular(10.0),
                      child: NetworkOrAssetImage(
                        imageUrl: item.videoElem?.snapshotUrl ?? '',
                        width: 120,
                        placeholderAsset: 'assets/images/bk.jpg',
                      ),
                    ),
                    const Align(
                      alignment: Alignment.center,
                      child: Icon(
                        Icons.play_circle,
                        color: Colors.white,
                        size: 30.0,
                      ),
                    ),
                  ],
                ),
              ),
              onTap: () {
                showGeneralDialog(
                  context: context,
                  // barrierDismissible: true,
                  barrierColor: Colors.black.withAlpha((1.0 * 255).round()),
                  pageBuilder: (_, __, ___) {
                    return SafeArea(
                      child: PreviewVideo(
                        videoUrl: item.videoElem?.videoUrl ?? '',
                        width: item.videoElem?.snapshotWidth?.toDouble(),
                        height: item.videoElem?.snapshotHeight?.toDouble(),
                      ),
                    );
                  },
                  transitionBuilder: (_, anim, __, child) {
                    return FadeTransition(opacity: anim, child: child);
                  },
                  transitionDuration: const Duration(milliseconds: 200),
                );
              },
              onLongPress: () {
                contextMenuDialog();
              },
            ),
          ),
        ));
      }
      // 语音模板=4
      else if (item.elemType == 4) {
        final durationMs = item.soundElem?.duration ?? 0;
        final durationSeconds = (durationMs / 1000).round();
        final maxWidth = (durationSeconds / 60 * 230).clamp(80.0, 230.0);

        List<Widget> audiobody = [
          Ink(
            decoration: BoxDecoration(
              color: !(item.isSelf ?? false) ? const Color(0xFFFFFFFF) : const Color(0xFF89E45B),
              borderRadius: BorderRadius.circular(10.0),
            ),
            child: InkWell(
              overlayColor: WidgetStateProperty.all(Colors.transparent),
              borderRadius: BorderRadius.circular(10.0),
              child: Container(
                padding: const EdgeInsets.all(10.0),
                constraints: BoxConstraints(
                  maxWidth: maxWidth,
                  // maxWidth: (item.soundElem!.duration! / 1000) / 60 * 230,
                ),
                child: Row(
                  mainAxisAlignment: !(item.isSelf ?? false) ? MainAxisAlignment.start : MainAxisAlignment.end,
                  children: !(item.isSelf ?? false)
                      ? [
                          const Icon(Icons.multitrack_audio),
                          const SizedBox(
                            width: 5.0,
                          ),
                          Text('$durationSeconds"'),
                        ]
                      : [
                          Text('$durationSeconds"'),
                          const SizedBox(
                            width: 5.0,
                          ),
                          const Icon(Icons.multitrack_audio),
                        ],
                ),
              ),
              onTap: () async {
                final locUrl = item.soundElem?.path ?? '';
                final netUrl = item.soundElem?.url ?? '';
                final msgId = item.id ?? '${item.timestamp ?? 0}';
                logger.w('本地地址$locUrl');
                logger.w('网络地址$netUrl');
                if (locUrl.isNotEmpty) {
                  voicePlayingMap[msgId] = true;
                  await AudioPlayerService().playLocal(locUrl);
                  voicePlayingMap[msgId] = false;
                } else if (netUrl.isNotEmpty) {
                  voicePlayingMap[msgId] = true;
                  await AudioPlayerService().playNetwork(netUrl);
                  voicePlayingMap[msgId] = false;
                } else {
                  MyDialog.toast('音频文件已过期', icon: Icon(Icons.warning), style: ToastStyle(backgroundColor: Colors.red.withAlpha(200)));
                }
              },
              onLongPress: () {
                contextMenuDialog();
              },
            ),
          ),
          const SizedBox(
            width: 5.0,
          ),

          // FStyle.badge(0, isdot: true),
        ];

        if (item.isSelf ?? false) {
          // 内容反转
          audiobody = audiobody.reversed.toList();
        } else {
          audiobody = audiobody;
        }

        msgtpl.add(RenderChatItem(
            data: item,
            child: Row(
              mainAxisAlignment: !(item.isSelf ?? false) ? MainAxisAlignment.start : MainAxisAlignment.end,
              children: audiobody,
            )));
      }
      // 分享团购商品
      else if (item.elemType == 2 && item.cloudCustomData == SummaryType.shareTuangou) {
        // final makeJson = jsonEncode({
        //   "price": shopObj['price'],
        //   "title": shopObj['name'],
        //   "url": shopObj['pic'],
        //   "sell": Utils.graceNumber(int.parse(shopObj['sales'] ?? '0')),
        //   "goodsId": shopObj['id'],
        //   "userID": Get.find<ImUserInfoController>().userID.value,
        // });
        final obj = jsonDecode(item.customElem!.data!);
        logger.e(obj);
        final goodsId = obj['goodsId'];
        final userID = obj['userID'];
        final url = obj['url'];
        final title = obj['title'];
        final price = obj['price'];
        final sell = Utils.graceNumber(int.tryParse(obj['sell'])!);
        msgtpl.add(RenderChatItem(
          data: item,
          child: GestureDetector(
            onTap: () {
              // 这里带上分享人的ID
              Get.toNamed('/goods', arguments: {'goodsId': goodsId, 'userID': userID});
            },
            child: Container(
              width: 160,
              clipBehavior: Clip.antiAlias,
              decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(15.0), boxShadow: [
                BoxShadow(
                  color: Colors.black.withAlpha(5),
                  offset: Offset(0.0, 1.0),
                  blurRadius: 1.0,
                  spreadRadius: 0.0,
                ),
              ]),
              child: Column(
                children: [
                  NetworkOrAssetImage(
                    imageUrl: url,
                    placeholderAsset: 'assets/images/bk.jpg',
                    width: 160.0,
                  ),
                  Container(
                    padding: EdgeInsets.symmetric(horizontal: 10.0, vertical: 5.0),
                    child: Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      spacing: 5.0,
                      children: [
                        Text(
                          '$title',
                          style: TextStyle(fontSize: 14.0, height: 1.2),
                          maxLines: 2,
                          overflow: TextOverflow.ellipsis,
                        ),
                        Row(
                          mainAxisAlignment: MainAxisAlignment.spaceBetween,
                          children: [
                            Flexible(
                              child: Text.rich(
                                overflow: TextOverflow.ellipsis,
                                maxLines: 1,
                                TextSpan(style: TextStyle(color: Colors.red, fontSize: 12.0, fontWeight: FontWeight.w700, fontFamily: 'Arial'), children: [
                                  TextSpan(text: '¥'),
                                  TextSpan(
                                      text: '$price',
                                      style: TextStyle(
                                        fontSize: 14.0,
                                      )),
                                ]),
                              ),
                            ),
                            SizedBox(
                              width: 5,
                            ),
                            Text(
                              '已售$sell件',
                              style: TextStyle(color: Colors.grey, fontSize: 10.0),
                            ),
                          ],
                        ),
                      ],
                    ),
                  )
                ],
              ),
            ),
          ),
        ));
      }
      // 分享短视频
      else if (item.elemType == 2 && item.cloudCustomData == SummaryType.shareVideo) {
        /// {imgUrl,videoUrl,width,height}
        final obj = jsonDecode(item.customElem!.data!);
        logger.e(obj);
        final videoId = obj['videoId'];
        final videoUrl = obj['videoUrl'];
        final imgUrl = obj['imgUrl'];
        final width = obj['width'] as num;
        final height = obj['height'] as num;
        final isHorizontal = width > height;
        msgtpl.add(RenderChatItem(
          data: item,
          child: Ink(
            child: InkWell(
              overlayColor: WidgetStateProperty.all(Colors.transparent),
              child: SizedBox(
                width: 120.0,
                child: Stack(
                  alignment: Alignment.center,
                  children: [
                    ClipRRect(
                      borderRadius: BorderRadius.circular(10.0),
                      child: Container(
                        width: 120,
                        height: 240,
                        color: Colors.black,
                        child: NetworkOrAssetImage(
                          imageUrl: imgUrl,
                          fit: isHorizontal ? BoxFit.contain : BoxFit.cover,
                          placeholderAsset: 'assets/images/bk.jpg',
                        ),
                      ),
                    ),
                    const Align(
                      alignment: Alignment.center,
                      child: Icon(
                        Icons.play_circle,
                        color: Colors.white,
                        size: 30.0,
                      ),
                    ),
                  ],
                ),
              ),
              onTap: () {
                Get.toNamed('/videoDetail', arguments: {'videoId': videoId});
                // showGeneralDialog(
                //   context: context,
                //   barrierColor: Colors.black.withAlpha((1.0 * 255).round()),
                //   pageBuilder: (_, __, ___) {
                //     return SafeArea(
                //       bottom: true,
                //       child: Padding(
                //         padding: const EdgeInsets.only(bottom: 4),
                //         child: PreviewVideo(
                //           videoUrl: videoUrl,
                //           width: width.toDouble(),
                //           height: height.toDouble(),
                //         ),
                //       ),
                //     );
                //   },
                //   transitionBuilder: (_, anim, __, child) {
                //     return FadeTransition(opacity: anim, child: child);
                //   },
                //   transitionDuration: const Duration(milliseconds: 200),
                // );
              },
              // onLongPress: () {
              // contextMenuDialog();
              // },
            ),
          ),
        ));
      }
      // 红包模板=自定义=2；
      else if (item.elemType == 2 && item.cloudCustomData == SummaryType.hongbao) {
        final obj = jsonDecode(item.customElem!.data!);
        final open = obj['open'] ?? false;
        final remark = obj['remark'];
        // final maxNum = obj['maxNum'];
        msgtpl.add(RenderChatItem(
          data: item,
          child: Ink(
            decoration: BoxDecoration(
              color: const Color(0xFFFF7F43),
              borderRadius: BorderRadius.circular(10.0),
            ),
            child: InkWell(
              overlayColor: WidgetStateProperty.all(Colors.transparent),
              borderRadius: BorderRadius.circular(10.0),
              child: Container(
                constraints: const BoxConstraints(
                  maxWidth: 210.0,
                ),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Container(
                      width: 210.0,
                      padding: const EdgeInsets.all(10.0),
                      child: Row(
                        children: <Widget>[
                          open
                              ? Icon(Icons.check_circle, size: 32.0, color: Colors.white70)
                              : Image.asset(
                                  'assets/images/hbico.png',
                                  width: 32.0,
                                  fit: BoxFit.contain,
                                ),
                          const SizedBox(width: 10),
                          Expanded(
                            child: Text(
                              '$remark',
                              style: const TextStyle(color: Colors.white, fontSize: 14.0),
                              maxLines: 1,
                              overflow: TextOverflow.ellipsis,
                            ),
                          ),
                        ],
                      ),
                    ),
                    Container(
                      margin: const EdgeInsets.symmetric(horizontal: 10.0),
                      padding: const EdgeInsets.symmetric(vertical: 5.0),
                      width: double.infinity,
                      decoration: const BoxDecoration(border: Border(top: BorderSide(color: Colors.white30, width: .5))),
                      child: const Text(
                        '红包',
                        style: TextStyle(color: Colors.white70, fontSize: 11.0),
                      ),
                    ),
                  ],
                ),
              ),
              onTap: () {
                receiveRedPacketDialog(item);
              },
              onLongPress: () {
                contextMenuDialog();
              },
            ),
          ),
        ));
      }
      // 位置模板=7
      else if (item.elemType == 7) {
        msgtpl.add(RenderChatItem(
          data: item,
          child: Ink(
            decoration: BoxDecoration(
              color: const Color(0xFFFFFFFF),
              borderRadius: BorderRadius.circular(10.0),
            ),
            child: InkWell(
              // splashColor: Colors.transparent,
              overlayColor: WidgetStateProperty.all(Colors.transparent),
              borderRadius: BorderRadius.circular(10.0),
              child: Container(
                constraints: const BoxConstraints(
                  maxWidth: 210.0,
                ),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Container(
                      padding: const EdgeInsets.symmetric(
                        horizontal: 10.0,
                        vertical: 5.0,
                      ),
                      child: Column(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: <Widget>[
                          Text(
                            item.locationElem?.desc ?? '位置信息异常',
                            overflow: TextOverflow.ellipsis,
                          ),
                          Text(
                            "${item.locationElem?.latitude},${item.locationElem?.longitude}",
                            style: const TextStyle(color: Colors.grey, fontSize: 12.0),
                            overflow: TextOverflow.ellipsis,
                          ),
                        ],
                      ),
                    ),
                    ClipRRect(
                      borderRadius: const BorderRadius.vertical(bottom: Radius.circular(10.0)),
                      child: Image.asset('assets/images/map.jpg', width: 210.0, height: 70.0, fit: BoxFit.cover),
                    )
                  ],
                ),
              ),
              onTap: () {
                MyDialog.toast('该功能暂未支持~', icon: Icon(Icons.warning), style: ToastStyle(backgroundColor: Colors.red.withAlpha(200)));
              },
              onLongPress: () {
                contextMenuDialog();
              },
            ),
          ),
        ));
      }
    }
    return msgtpl;
  }

  // 表情列表集合
  List<Widget> renderEmojWidget() {
    return [
      // Tab切换
      Container(
        padding: const EdgeInsets.symmetric(horizontal: 5.0),
        child: Row(
          children: emoJson.map((item) {
            return InkWell(
              child: Container(
                margin: const EdgeInsets.all(5.0),
                alignment: Alignment.center,
                height: 40.0,
                width: 40.0,
                decoration: BoxDecoration(color: item['selected'] ? Colors.white : Colors.transparent, borderRadius: BorderRadius.circular(5.0)),
                child: item['index'] == 0
                    ? Text(
                        item['pathLabel'],
                        style: const TextStyle(fontSize: 22.0),
                      )
                    : Image.asset(item['pathLabel'], height: 24.0, width: 24.0, fit: BoxFit.cover),
              ),
              onTap: () {
                handleEmojTab(item['index']);
              },
            );
          }).toList(),
        ),
      ),
      Expanded(
        child: Container(
          decoration: BoxDecoration(
            color: Colors.grey[200],
            border: const Border(top: BorderSide(color: Colors.black54, width: .1)),
          ),
          child: ListView(
            controller: emojController,
            padding: const EdgeInsets.all(10.0),
            children: emoJson.map((item) {
              return Visibility(
                visible: item['selected'],
                child: GridView(
                  shrinkWrap: true,
                  physics: const NeverScrollableScrollPhysics(),
                  gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                    // 横轴元素个数
                    crossAxisCount: item['type'] == 'emoj' ? 8 : 5,
                    // 纵轴间距
                    mainAxisSpacing: 5.0,
                    // 横轴间距
                    crossAxisSpacing: 5.0,
                    // 子组件宽高比例
                    childAspectRatio: 1,
                  ),
                  children: item['nodes'].map<Widget>((emoj) {
                    if (item['type'] == 'emoj') {
                      return Material(
                        type: MaterialType.transparency,
                        child: InkWell(
                          borderRadius: BorderRadius.circular(5.0),
                          child: Container(
                            alignment: Alignment.center,
                            height: 40.0,
                            width: 40.0,
                            child: Text(
                              emoj,
                              style: const TextStyle(fontSize: 24.0),
                            ),
                          ),
                          onTap: () {
                            handleEmojClick(emoj);
                          },
                        ),
                      );
                    } else {
                      return Material(
                        type: MaterialType.transparency,
                        child: InkWell(
                          borderRadius: BorderRadius.circular(5.0),
                          child: Container(
                            alignment: Alignment.center,
                            padding: const EdgeInsets.all(5.0),
                            height: 68.0,
                            width: 68.0,
                            child: Image.asset(emoj),
                          ),
                          onTap: () {
                            handleGIFClick(emoj, item['index']);
                          },
                        ),
                      );
                    }
                  }).toList(),
                ),
              );
            }).toList(),
          ),
        ),
      ),
    ];
  }

  // 选择功能列表
  List<Widget> renderChooseWidget() {
    return [
      Expanded(
        child: Container(
          padding: const EdgeInsets.fromLTRB(30.0, 35.0, 30.0, 15.0),
          decoration: BoxDecoration(
            color: Colors.grey[200],
            border: const Border(top: BorderSide(color: Colors.black38, width: .1)),
          ),
          child: GridView(
            shrinkWrap: true,
            physics: const NeverScrollableScrollPhysics(),
            gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
              // 横轴元素个数
              crossAxisCount: 4,
              // 纵轴间距
              mainAxisSpacing: 30.0,
              // 横轴间距
              crossAxisSpacing: 25.0,
              // 子组件宽高比例
              childAspectRatio: .8,
            ),
            children: chooseOptions.map((item) {
              return Column(
                children: [
                  Expanded(
                    child: Material(
                      type: MaterialType.transparency,
                      child: Ink(
                        decoration: BoxDecoration(
                          color: Colors.white,
                          borderRadius: BorderRadius.circular(15.0),
                        ),
                        child: InkWell(
                          borderRadius: BorderRadius.circular(15.0),
                          child: Image.asset(item['icon'], height: 40.0, fit: BoxFit.cover),
                          onTap: () {
                            handleChooseAction(item['key']);
                          },
                        ),
                      ),
                    ),
                  ),
                  const SizedBox(height: 5.0),
                  Text(
                    item['name'],
                    style: const TextStyle(color: Colors.black87, fontSize: 12.0),
                  )
                ],
              );
            }).toList(),
          ),
        ),
      ),
    ];
  }

  /* ---------- { 聊天消息模块 } ---------- */
  // 聊天消息滚动到底部
  // void scrollToBottom() async {
  //   chatList = await fetchChatList();
  //   chatController.animateTo(isNeedScrollBottom ? 0 : chatController.position.maxScrollExtent,
  //       duration: const Duration(milliseconds: 200), curve: Curves.easeIn);
  // }

  // void scrollToBottom() {
  //   Future.delayed(Duration(milliseconds: 300), () {
  //     if (chatController.hasClients) {
  //       chatController.animateTo(
  //         // 0, // reverse: true 时滚动到底部是 offset: 0
  //         chatController.position.maxScrollExtent,
  //         duration: Duration(milliseconds: 300),
  //         curve: Curves.easeOut,
  //       );
  //     }
  //   });
  // }

  // 点击消息区域
  void handleClickChatArea() {
    hideKeyboard();
    setState(() {
      toolbarEnable = false;
    });
  }

  /* ---------- { 底部Toolbar模块 } ---------- */
  // 光标处插入内容
  void insertTextAtCursor(String html) {
    var editorNotifier = editorController.value; // The current value stored in this notifier.
    var start = editorNotifier.selection.baseOffset;
    var end = editorNotifier.selection.extentOffset;
    if (editorNotifier.selection.isValid) {
      String newText = '';
      if (editorNotifier.selection.isCollapsed) {
        if (end > 0) {
          newText += editorNotifier.text.substring(0, end);
        }
        newText += html;
        if (editorNotifier.text.length > end) {
          newText += editorNotifier.text.substring(end, editorNotifier.text.length);
        }
      } else {
        newText = editorNotifier.text.replaceRange(start, end, html);
        end = start;
      }
      editorController.value =
          editorNotifier.copyWith(text: newText, selection: editorNotifier.selection.copyWith(baseOffset: end + html.length, extentOffset: end + html.length));
    } else {
      editorController.value = TextEditingValue(
        text: html,
        selection: TextSelection.fromPosition(TextPosition(offset: html.length)),
      );
    }
  }

  // 发送消息队列
  void sendMessage(message) async {
    final canSend = checkSend();
    if (!canSend) {
      final baseStyle = MyDialog.theme.toastStyle?.top();
      MyDialog.toast(
        '对方未回关或回复,只能发送一条消息',
        icon: const Icon(Icons.check_circle),
        duration: Duration(milliseconds: 5000),
        style: baseStyle?.copyWith(
          backgroundColor: Colors.red.withAlpha(200),
        ),
      );

      print('禁止发送$canSend');
      return;
    }
    // 待插入的消息
    List<V2TimMessage> messagesToInsert = [];
    V2TimMessage? lastRealMsg;

    for (var msg in controller.chatList) {
      if (msg.localCustomData != 'time_label') {
        lastRealMsg = msg;
        break;
      }
    }

    // 如果有数据，检测时间，是否需要插入伪消息
    if (lastRealMsg != null &&
        needInsertTimeLabel(
          (lastRealMsg.timestamp ?? 0) * 1000, // 转为毫秒级
          DateTime.now().millisecondsSinceEpoch,
        )) {
      // 消息时间间隔超过3分钟插入伪消息
      final showLabel = Utils.formatChatTime(DateTime.now().millisecondsSinceEpoch ~/ 1000);
      final resMsg = await IMMessage().insertTimeLabel(showLabel, selfUserId);
      messagesToInsert.add(resMsg.data);
    } else {
      // 没数据的时候直接插入伪消息
      final showLabel = Utils.formatChatTime(DateTime.now().millisecondsSinceEpoch ~/ 1000);

      final resMsg = await IMMessage().insertTimeLabel(showLabel, selfUserId);
      messagesToInsert.add(resMsg.data);
    }

    // 不需要时间标签
    // 消息类型，message['type']
    late final ImResult res;
    res = await IMMessage().sendMessage(
      msg: message,
      toUserID: arguments.value.userID,
      cloudCustomData: canSend == true ? ConversationType.noFriend.name : '',
    );

    if (res.success && res.data != null) {
      messagesToInsert.insert(0, res.data); // 加入消息本体
      // messagesToInsert.add(res.data); // 加入消息本体

      controller.chatList.insertAll(0, messagesToInsert);
      // controller.chatList.addAll(messagesToInsert);

      controller.scrollToBottom();
      print('发送成功');
    } else {
      print('消息发送失败: ${res.code} - ${res.desc}');
    }
  }

  bool needInsertTimeLabel(int lastTimestamp, int newTimestamp, {int interval = 3 * 60}) {
    return (newTimestamp - lastTimestamp) > interval * 1000;
  }

  // 隐藏键盘
  void hideKeyboard() {
    if (editorFocusNode.hasFocus) {
      editorFocusNode.unfocus();
    }
  }

  // 表情/选择切换
  void handleEmojChooseState(index) {
    hideKeyboard();
    setState(() {
      toolbarEnable = true;
      toolbarIndex = index;
      voiceBtnEnable = false;
    });
    controller.scrollToBottom();
  }

  // 表情Tab切换
  void handleEmojTab(index) {
    var emols = emoJson;
    for (var i = 0, len = emols.length; i < len; i++) {
      emols[i]['selected'] = false;
    }
    emols[index]['selected'] = true;
    setState(() {
      emoJson = emols;
    });
    emojController.jumpTo(0);
  }

  // 点击表情插入到输入框
  void handleEmojClick(emoj) {
    insertTextAtCursor(emoj);
  }

  // 点击Gif大图发送=8
  void handleGIFClick(gifpath, index) async {
    // 消息队列
    // Map message = {
    //   'contentType': 8,
    //   'content': gifpath,
    // };
    final res = await IMMessage().createFaceMessage(data: gifpath, index: index);
    if (res.success) {
      sendMessage(res.data?.messageInfo);
    }
  }

  // 发送文本消息=1
  void handleSubmit() async {
    if (editorController.text.isEmpty) return;
    // 消息队列
    // Map message = {
    //   'contentType': 1,
    //   'content': editorController.text,
    // };
    final res = await IMMessage().createTextMessage(text: editorController.text);
    if (res.success) {
      sendMessage(res.data?.messageInfo);
      editorController.clear();
    }
  }

  // 发送图片消息=3
  void sendImage(imgPath) async {
    final resImg = await IMMessage().createImageMessage(imagePath: imgPath);
    if (resImg.success) {
      sendMessage(resImg.data?.messageInfo);
    }
  }

  // 发送视频消息=5
  void sendVideo(videoFilePath, type, duration, snapshotPath) async {
    final resImg = await IMMessage().createVideoMessage(
      videoFilePath: videoFilePath,
      type: type,
      duration: duration,
      snapshotPath: snapshotPath,
    );
    if (resImg.success) {
      sendMessage(resImg.data?.messageInfo);
    }
  }

  // 底部操作蓝选择区操作
  void handleChooseAction(key) {
    MyDialog.toast('$key');
    switch (key) {
      case 'photo':
        // ....
        pickFile(context);
        break;
      case 'camera':
        // ....
        break;
      case 'redpacket':
        sendRedPacketDialog();
        break;
    }
  }

  ///从相册选取图片/视频
  void pickFile(BuildContext context) async {
    final pickedAssets = await AssetPicker.pickAssets(
      context,
      pickerConfig: AssetPickerConfig(
        textDelegate: const AssetPickerTextDelegate(),
        pathNameBuilder: (AssetPathEntity album) {
          return Utils.translateAlbumName(album);
        },
        maxAssets: 5,
        requestType: RequestType.common,
        filterOptions: FilterOptionGroup(
          imageOption: const FilterOption(),
          videoOption: const FilterOption(
            durationConstraint: DurationConstraint(
              max: Duration(seconds: 120),
            ),
          ),
        ),
      ),
    );

    if (pickedAssets != null && pickedAssets.isNotEmpty) {
      for (final asset in pickedAssets) {
        switch (asset.type) {
          case AssetType.image:
            print("选中了图片：${asset.title}");
            var file = await asset.file;
            if (file != null) {
              var fileSizeInBytes = await file.length();
              var sizeInMB = fileSizeInBytes / (1024 * 1024);
              if (sizeInMB > 28) {
                MyDialog.toast('图片大小不能超过28MB', icon: const Icon(Icons.check_circle), style: ToastStyle(backgroundColor: Colors.red.withAlpha(200)));
              } else {
                print("图片合法，大小：$sizeInMB MB");
                // 执行发送逻辑
                sendImage(file.path);
              }
            }

            break;
          case AssetType.video:
            print("选中了视频：${asset.title}");
            var file = await asset.file;
            if (file != null) {
              var fileSizeInBytes = await file.length();
              var sizeInMB = fileSizeInBytes / (1024 * 1024);
              if (sizeInMB > 100) {
                MyDialog.toast('视频大小不能超过100MB', icon: const Icon(Icons.check_circle), style: ToastStyle(backgroundColor: Colors.red.withAlpha(200)));
              } else {
                print("视频合法，大小：$sizeInMB MB");
                // 执行发送逻辑
                var snapshot = await generateVideoThumbnail(file.path);
                String? mimeType = await asset.mimeTypeAsync;
                String vdType = mimeType?.split('/').last ?? 'mp4';
                print(vdType);
                sendVideo(file.path, vdType, asset.duration, snapshot);
              }
            }
            break;
          default:
            print("不支持的类型：${asset.type}");
        }
      }
      // final asset = pickedAssets.first;
      // final file = await asset.file; // 获取实际文件
      // if (file != null) {
      //   final fileSizeInBytes = await file.length();
      //   final sizeInMB = fileSizeInBytes / (1024 * 1024);
      //   if (sizeInMB > 100) {
      //     MyDialog.toast('图片大小不能超过100MB', icon: const Icon(Icons.check_circle), style: ToastStyle(backgroundColor: Colors.red.withAlpha(200)));
      //   } else {
      //     print("图片合法，大小：$sizeInMB MB");
      //     //走upload(file)上传图片拿到url地址
      //     // file;
      //   }
      // }
    }
  }

  /* ---------- { 弹窗功能模块 } ---------- */
  // 红包弹窗
  void receiveRedPacketDialog(data) {
    showDialog(
        context: context,
        builder: (context) {
          return Material(
              type: MaterialType.transparency,
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  Container(
                    width: double.infinity,
                    margin: const EdgeInsets.symmetric(horizontal: 50.0),
                    padding: const EdgeInsets.symmetric(vertical: 50.0),
                    decoration: const BoxDecoration(
                      color: Color(0xFFFF7F43),
                      borderRadius: BorderRadius.all(Radius.circular(12.0)),
                    ),
                    child: Column(
                      children: [
                        ClipRRect(
                          borderRadius: BorderRadius.circular(5.0),
                          child: Image.asset(data['avatar'], height: 40.0, width: 40.0, fit: BoxFit.cover),
                        ),
                        const SizedBox(
                          height: 5.0,
                        ),
                        Text(
                          data['author'],
                          style: const TextStyle(color: Color(0xFFFFF9C7), fontWeight: FontWeight.w600),
                        ),
                        Text(
                          data['content'],
                          style: const TextStyle(color: Color(0xFFFFF9C7), fontWeight: FontWeight.w500, fontSize: 20.0),
                        ),
                        SizedBox(
                          height: 100.0,
                        ),
                        AnimatedBuilder(
                          animation: animTurns,
                          builder: (context, child) {
                            return Transform(
                              transform: Matrix4.rotationY(animTurns.value),
                              alignment: Alignment.center,
                              child: FilledButton(
                                style: ButtonStyle(
                                  backgroundColor: WidgetStateProperty.all(const Color(0xFFFFF9C7)),
                                  padding: WidgetStateProperty.all(EdgeInsets.zero),
                                  minimumSize: WidgetStateProperty.all(const Size(80.0, 80.0)),
                                  shape: WidgetStateProperty.all(const CircleBorder()),
                                  elevation: WidgetStateProperty.all(3.0),
                                ),
                                child: Text(
                                  '開',
                                  style: TextStyle(color: Color(0xFF3B3B3B), fontSize: 28.0),
                                ),
                                onPressed: () {
                                  // 开始动画
                                  animController.repeat();
                                  // 模拟开红包逻辑，1 秒后停止动画
                                  Future.delayed(Duration(seconds: 1), () {
                                    animController.stop();
                                    animController.reset();
                                    Get.back();
                                  });
                                },
                              ),
                            );
                          },
                        ),
                      ],
                    ),
                  ),
                  GestureDetector(
                    child: Container(
                      margin: const EdgeInsets.only(top: 20.0),
                      height: 30.0,
                      width: 30.0,
                      decoration: BoxDecoration(
                        border: Border.all(color: Colors.white, width: 1.5),
                        borderRadius: BorderRadius.circular(50.0),
                      ),
                      child: const Icon(
                        Icons.close_outlined,
                        color: Colors.white,
                        size: 18.0,
                      ),
                    ),
                    onTap: () {
                      Navigator.of(context).pop();
                    },
                  )
                ],
              ));
        });
  }

  // 长按消息菜单
  void contextMenuDialog() {
    return;
    showDialog(
      context: context,
      builder: (context) {
        return SimpleDialog(
          backgroundColor: Colors.white,
          surfaceTintColor: Colors.white,
          contentPadding: const EdgeInsets.symmetric(vertical: 5.0),
          shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15.0)),
          children: [
            SimpleDialogOption(
              child: const Padding(padding: EdgeInsets.symmetric(vertical: 5.0), child: Text('复制')),
              onPressed: () {},
            ),
            SimpleDialogOption(
              child: const Padding(padding: EdgeInsets.symmetric(vertical: 5.0), child: Text('发送给朋友')),
              onPressed: () {},
            ),
            SimpleDialogOption(
              child: const Padding(padding: EdgeInsets.symmetric(vertical: 5.0), child: Text('收藏')),
              onPressed: () {},
            ),
            SimpleDialogOption(
              child: const Padding(padding: EdgeInsets.symmetric(vertical: 5.0), child: Text('删除')),
              onPressed: () {},
            ),
          ],
        );
      },
    );
  }

  // 发群红包弹窗
  void sendRedPacketDialog() {
    showModalBottomSheet(
      backgroundColor: Colors.grey[50],
      shape: const RoundedRectangleBorder(borderRadius: BorderRadius.vertical(top: Radius.circular(15.0))),
      showDragHandle: true,
      clipBehavior: Clip.hardEdge,
      isScrollControlled: true, // 屏幕最大高度
      constraints: BoxConstraints(
        maxHeight: MediaQuery.of(context).size.height - 180, // 自定义最大高度
      ),
      context: context,
      builder: (context) {
        return RedPacket(
          flag: false,
        );
      },
    );
  }

  /* ---------- { 其它功能模块 } ---------- */

  @override
  Widget build(BuildContext context) {
    return Stack(
      fit: StackFit.expand,
      children: [
        // 页面主体(聊天消息区/底部操作区)
        Scaffold(
          backgroundColor: Colors.grey[200],
          resizeToAvoidBottomInset: true, // 启用键盘自动避让
          appBar: AppBar(
            centerTitle: true,
            backgroundColor: Colors.transparent,
            foregroundColor: Colors.white,
            leading: IconButton(
              icon: Icon(
                Icons.arrow_back_ios_rounded,
                size: 20.0,
              ),
              onPressed: () {
                Get.back();
              },
            ),
            titleSpacing: 1.0,
            title: Obx(() {
              return Text(
                // '${arguments['title']}',
                arguments.value.showName ?? '陌生人',
                style: const TextStyle(fontSize: 18.0, fontFamily: 'Arial'),
              );
            }),
            flexibleSpace: Container(
              decoration: const BoxDecoration(
                  gradient: LinearGradient(
                begin: Alignment.topLeft,
                end: Alignment.bottomRight,
                colors: [Color(0xFFBE4EFF), Color(0xFF1DFFC7)],
              )),
            ),
            actions: [
              // IconButton(
              //   icon: const Icon(
              //     Icons.more_horiz,
              //     color: Colors.white,
              //   ),
              //   onPressed: () async {
              //     final paddingTop = MediaQuery.of(Get.context!).padding.top;

              //     final selected = await showMenu(
              //       context: Get.context!,
              //       position: RelativeRect.fromLTRB(
              //         double.infinity,
              //         kToolbarHeight + paddingTop - 12,
              //         8,
              //         double.infinity,
              //       ),
              //       color: FStyle.primaryColor,
              //       elevation: 8,
              //       items: [
              //         PopupMenuItem<String>(
              //           value: 'report',
              //           child: Row(
              //             children: [
              //               Icon(Icons.report, color: Colors.white, size: 18),
              //               SizedBox(width: 8),
              //               Text(
              //                 '举报',
              //                 style: TextStyle(color: Colors.white),
              //               ),
              //             ],
              //           ),
              //         ),
              //         PopupMenuItem<String>(
              //           value: 'block',
              //           child: Row(
              //             children: [
              //               Icon(Icons.block, color: Colors.white, size: 18),
              //               SizedBox(width: 8),
              //               Text(
              //                 '拉黑',
              //                 style: TextStyle(color: Colors.white),
              //               ),
              //             ],
              //           ),
              //         ),
              //       ],
              //     );

              //     if (selected != null) {
              //       switch (selected) {
              //         case 'report':
              //           print('点击了举报');
              //           break;
              //         case 'block':
              //           print('点击了拉黑');
              //           break;
              //       }
              //     }
              //   },
              // ),
            ],
          ),
          body: Flex(
            direction: Axis.vertical,
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              // 渲染聊天消息
              // Expanded(
              //   child: ScrollConfiguration(
              //     behavior: CustomScrollBehavior(),
              //     child: GestureDetector(
              //       child: Obx(() {
              //         return ListView(
              //           reverse: true,
              //           controller: chatController,
              //           padding: const EdgeInsets.all(10.0),
              //           children: renderChatList(),
              //         );
              //       }),
              //       onTap: () {
              //         handleClickChatArea();
              //       },
              //     ),
              //   ),
              // ),

              // 聊天内容
              // Expanded(
              //   child: GestureDetector(
              //     behavior: HitTestBehavior.opaque,
              //     onTap: handleClickChatArea,
              //     child: LayoutBuilder(
              //       builder: (context, constraints) {
              //         return Obx(() {
              //           // final tipWidget = Builder(builder: (context) => Text(tips));

              //           final msgWidgets = renderChatList().reversed.toList();
              //           // if (controller.isFriend.value) {}
              //           return ListView(
              //             controller: chatController,
              //             reverse: true,
              //             padding: const EdgeInsets.all(10.0),
              //             children: [
              //               ConstrainedBox(
              //                 constraints: BoxConstraints(
              //                   minHeight: constraints.maxHeight - 20,
              //                 ),
              //                 child: Column(
              //                   mainAxisSize: MainAxisSize.min,
              //                   children: msgWidgets,
              //                 ),
              //               ),
              //             ],
              //           );
              //         });
              //       },
              //     ),
              //   ),
              // ),
              // 聊天内容
              Expanded(
                child: GestureDetector(
                  behavior: HitTestBehavior.opaque,
                  onTap: handleClickChatArea,
                  child: LayoutBuilder(
                    builder: (context, constraints) {
                      return Obx(() {
                        final showTipWidget = controller.followType.value;
                        const double tipHeight = 50; // 提示横幅固定高度

                        final msgWidgets = renderChatList().reversed.toList();

                        return Stack(
                          children: [
                            ListView(
                              controller: chatController,
                              reverse: true,
                              padding: EdgeInsets.only(
                                top: [1, 2].contains(showTipWidget) ? tipHeight + 10 : 0, // 动态预留顶部空间
                                left: 10,
                                right: 10,
                                bottom: 10,
                              ),
                              children: [
                                ConstrainedBox(
                                  constraints: BoxConstraints(
                                    minHeight: constraints.maxHeight - ([1, 2].contains(showTipWidget) ? tipHeight : 0),
                                  ),
                                  child: Column(
                                    mainAxisSize: MainAxisSize.min,
                                    children: msgWidgets,
                                  ),
                                ),
                              ],
                            ),
                            if ([1, 2].contains(showTipWidget))
                              Positioned(
                                top: 0,
                                left: 0,
                                right: 0,
                                height: tipHeight, // 固定高度
                                child: Container(
                                  color: Colors.white,
                                  padding: const EdgeInsets.symmetric(horizontal: 10),
                                  child: Row(
                                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                                    children: [
                                      Icon(
                                        Icons.error_outline,
                                        color: FStyle.primaryColor,
                                        size: 20,
                                      ),
                                      SizedBox(
                                        width: 10,
                                      ),
                                      Expanded(
                                        child: Text(
                                          '对方未回复或互关前仅可发送一条消息',
                                          style: const TextStyle(color: Colors.black, fontSize: 14),
                                          overflow: TextOverflow.ellipsis,
                                        ),
                                      ),
                                      Visibility(
                                        visible: [2].contains(showTipWidget),
                                        child: TextButton(
                                          style: TextButton.styleFrom(
                                            backgroundColor: FStyle.primaryColor,
                                            shape: RoundedRectangleBorder(
                                              borderRadius: BorderRadius.circular(8),
                                            ),
                                            padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
                                          ),
                                          onPressed: () async {
                                            // 回关
                                            final ctl = Get.find<ChatController>();

                                            final chatRes = await ImService.instance.followUser(userIDList: [arguments.value.userID!]);
                                            if (chatRes.success) {
                                              controller.isFriend.value = true;
                                              controller.followType.value = 3;
                                              final res = await ImService.instance.getConversation(conversationID: 'c2c_${arguments.value.userID}');
                                              if (res.success) {
                                                V2TimConversation conversation = res.data;
                                                if (conversation.conversationGroupList?.isNotEmpty ?? false) {
                                                  await ImService.instance.deleteConversationsFromGroup(
                                                    groupName: conversation.conversationGroupList!.first!,
                                                    conversationIDList: [conversation.conversationID],
                                                  );
                                                  await ctl.updateNoFriendMenu();
                                                  // 跳转到chat地址，销毁当前页面
                                                  Get.offAllNamed(
                                                    '/chat',
                                                    arguments: arguments.value,
                                                    predicate: (route) {
                                                      // 清理栈，只保留 `/`
                                                      return route.settings.name == '/';
                                                    },
                                                  );
                                                }
                                              }
                                            }
                                            // 回关
                                            // final res = await ImService.instance.followUser(userIDList: [arguments.value.userID!]);
                                            // if (res.success) {
                                            //   controller.isFriend.value = true;
                                            //   controller.followType.value = 3;
                                            //   if (arguments.value.conversationGroupList?.isNotEmpty == true) {
                                            //     //把会话数据从陌生人分组移除
                                            //     final ctl = Get.find<ChatController>();
                                            //     await ctl.removeNoFriend(conversationID: arguments.value.conversationID);
                                            //     ctl.updateNoFriendMenu();
                                            //     // 跳转到chat地址，销毁当前页面
                                            //     Get.offAllNamed(
                                            //       '/chat',
                                            //       arguments: arguments.value,
                                            //       predicate: (route) {
                                            //         // 清理栈，只保留 `/`
                                            //         return route.settings.name == '/';
                                            //       },
                                            //     );
                                            //   }
                                            // }
                                          },
                                          child: const Text('回关', style: TextStyle(color: Colors.white)),
                                        ),
                                      )
                                    ],
                                  ),
                                ),
                              ),
                          ],
                        );
                      });
                    },
                  ),
                ),
              ),

              // 底部操作栏
              Container(
                color: Colors.grey[100],
                child: SafeArea(
                  bottom: true,
                  child: Container(
                    decoration: BoxDecoration(
                      color: Colors.grey[100],
                      border: const Border(top: BorderSide(color: Colors.black38, width: .1)),
                    ),
                    child: Column(
                      children: [
                        // 输入框编辑器模块
                        Container(
                          padding: const EdgeInsets.all(10.0),
                          child: Row(
                            children: [
                              InkWell(
                                child: Icon(
                                  // voiceBtnEnable ? Icons.keyboard_outlined : Icons.contactless_outlined,
                                  Icons.keyboard_outlined,
                                  color: const Color(0xFF3B3B3B),
                                  size: 30.0,
                                ),
                                onTap: () {
                                  setState(() {
                                    toolbarEnable = false;
                                    if (editorFocusNode.hasFocus) {
                                      editorFocusNode.unfocus();
                                    } else {
                                      editorFocusNode.requestFocus();
                                    }
                                    if (toolbarEnable) {
                                      // voiceBtnEnable = false;
                                      // editorFocusNode.requestFocus();
                                      // editorFocusNode.requestFocus();
                                    } else {
                                      // voiceBtnEnable = true;
                                      // toolbarEnable = true;

                                      // editorFocusNode.unfocus();
                                    }
                                  });
                                },
                              ),
                              const SizedBox(
                                width: 10.0,
                              ),
                              Expanded(
                                child: Container(
                                  constraints: const BoxConstraints(minHeight: 40.0),
                                  decoration: BoxDecoration(
                                    color: Colors.white,
                                    borderRadius: BorderRadius.circular(5),
                                  ),
                                  child: Stack(
                                    children: [
                                      // 输入框
                                      Offstage(
                                        offstage: voiceBtnEnable,
                                        child: TextField(
                                          decoration: const InputDecoration(
                                            isDense: true,
                                            hoverColor: Colors.transparent,
                                            contentPadding: EdgeInsets.all(8.0),
                                            border: OutlineInputBorder(borderSide: BorderSide.none),
                                          ),
                                          style: const TextStyle(
                                            fontSize: 16.0,
                                          ),
                                          maxLines: null,
                                          controller: editorController,
                                          focusNode: editorFocusNode,
                                          cursorColor: const Color(0xFF07C160),
                                          onChanged: (value) {},
                                        ),
                                      ),
                                      // 语音
                                      Offstage(
                                        offstage: !voiceBtnEnable,
                                        child: GestureDetector(
                                          child: Container(
                                            decoration: BoxDecoration(
                                              color: Colors.white,
                                              borderRadius: BorderRadius.circular(5),
                                            ),
                                            alignment: Alignment.center,
                                            height: 40.0,
                                            width: double.infinity,
                                            child: Text(
                                              voiceTypeMap[voiceType],
                                              style: const TextStyle(fontSize: 15.0),
                                            ),
                                          ),
                                          onPanStart: (details) {
                                            setState(() {
                                              voiceType = 1;
                                              voicePanelEnable = true;
                                            });
                                          },
                                          onPanUpdate: (details) {
                                            Offset pos = details.globalPosition;
                                            double swipeY = MediaQuery.of(context).size.height - 120;
                                            double swipeX = MediaQuery.of(context).size.width / 2 + 50;
                                            setState(() {
                                              if (pos.dy >= swipeY) {
                                                voiceType = 1; // 松开发送
                                              } else if (pos.dy < swipeY && pos.dx < swipeX) {
                                                voiceType = 2; // 左滑松开取消
                                              } else if (pos.dy < swipeY && pos.dx >= swipeX) {
                                                voiceType = 3; // 右滑语音转文字
                                              }
                                            });
                                          },
                                          onPanEnd: (details) {
                                            // print('停止录音');
                                            setState(() {
                                              switch (voiceType) {
                                                case 1:
                                                  MyDialog.toast('发送录音文件');
                                                  voicePanelEnable = false;
                                                  break;
                                                case 2:
                                                  MyDialog.toast('取消发送');
                                                  voicePanelEnable = false;
                                                  break;
                                                case 3:
                                                  MyDialog.toast('语音转文字');
                                                  voicePanelEnable = true;
                                                  voiceToTransfer = true;
                                                  break;
                                              }
                                              voiceType = 0;
                                            });
                                          },
                                        ),
                                      ),
                                    ],
                                  ),
                                ),
                              ),
                              const SizedBox(
                                width: 10.0,
                              ),

                              // InkWell(
                              //   child: const Icon(
                              //     Icons.add_reaction_rounded,
                              //     color: Color(0xFF3B3B3B),
                              //     size: 30.0,
                              //   ),
                              //   onTap: () {
                              //     handleEmojChooseState(0);
                              //   },
                              // ),
                              // const SizedBox(
                              //   width: 8.0,
                              // ),

                              // InkWell(
                              //   child: const Icon(
                              //     Icons.add,
                              //     color: Color(0xFF3B3B3B),
                              //     size: 30.0,
                              //   ),
                              //   onTap: () {
                              //     handleEmojChooseState(1);
                              //   },
                              // ),
                              const SizedBox(
                                width: 8.0,
                              ),
                              InkWell(
                                child: Container(
                                  height: 25.0,
                                  width: 25.0,
                                  decoration: BoxDecoration(
                                    color: const Color(0xFF07C160),
                                    borderRadius: BorderRadius.circular(20.0),
                                  ),
                                  child: const Icon(
                                    Icons.arrow_upward,
                                    color: Colors.white,
                                    size: 20.0,
                                  ),
                                ),
                                onTap: () {
                                  handleSubmit();
                                },
                              ),
                            ],
                          ),
                        ),

                        // 表情+选择模块
                        Visibility(
                          visible: toolbarEnable,
                          child: SizedBox(
                            height: keyboardHeight,
                            child: Column(
                              children: toolbarIndex == 0 ? renderEmojWidget() : renderChooseWidget(),
                            ),
                          ),
                        )
                      ],
                    ),
                  ),
                ),
              )
            ],
          ),
        ),
        // 录音主体(按住说话/松开取消/语音转文本)
        IgnorePointer(
          ignoring: false,
          child: Visibility(
            visible: voicePanelEnable,
            child: Material(
              color: const Color(0xDD1B1B1B),
              child: Stack(
                children: [
                  // 取消发送+语音转文字
                  Positioned(
                    bottom: 120,
                    left: 30,
                    right: 30,
                    child: Visibility(
                      visible: !voiceToTransfer,
                      child: Column(
                        crossAxisAlignment: voiceType == 2 ? CrossAxisAlignment.start : CrossAxisAlignment.center,
                        children: [
                          // 语音动画层
                          Stack(
                            alignment: Alignment.bottomCenter,
                            children: [
                              AnimatedContainer(
                                duration: Duration(milliseconds: 200),
                                height: 70.0,
                                width: voiceType == 2 ? 70.0 : 200.0,
                                decoration: BoxDecoration(
                                  color: voiceType == 2 ? Colors.red : Color(0xFF89E45B),
                                  borderRadius: BorderRadius.circular(15.0),
                                ),
                                clipBehavior: Clip.antiAlias,
                                child: Row(
                                  mainAxisAlignment: MainAxisAlignment.center,
                                  children: [
                                    Image.asset('assets/images/voice_waves.gif', height: 23.0, width: voiceType == 2 ? 30.0 : 70.0, fit: BoxFit.cover)
                                  ],
                                ),
                              ),
                              RotatedBox(
                                quarterTurns: 0,
                                child: CustomPaint(painter: ArrowShape(arrowColor: voiceType == 2 ? Colors.red : Color(0xFF89E45B), arrowSize: 10.0)),
                              )
                            ],
                          ),
                          const SizedBox(
                            height: 50.0,
                          ),
                          // 操作项
                          Row(
                            mainAxisAlignment: MainAxisAlignment.spaceBetween,
                            children: [
                              // 取消发送
                              Container(
                                height: 60.0,
                                width: 60.0,
                                decoration: BoxDecoration(
                                  borderRadius: BorderRadius.circular(50.0),
                                  color: voiceType == 2 ? Colors.red : Colors.black38,
                                ),
                                child: Icon(
                                  Icons.close,
                                  color: Colors.white54,
                                ),
                              ),
                              // 语音转文字
                              Container(
                                height: 60.0,
                                width: 60.0,
                                decoration: BoxDecoration(
                                  borderRadius: BorderRadius.circular(50.0),
                                  color: voiceType == 3 ? Color(0xFF89E45B) : Colors.black38,
                                ),
                                child: Icon(
                                  Icons.translate,
                                  color: Colors.white54,
                                ),
                              ),
                            ],
                          ),
                        ],
                      ),
                    ),
                  ),
                  // 语音转文字(识别结果状态)
                  Positioned(
                    bottom: 120,
                    left: 30,
                    right: 30,
                    child: Visibility(
                      visible: voiceToTransfer,
                      child: Column(
                        children: [
                          // 提示结果
                          Stack(
                            children: [
                              Container(
                                height: 100.0,
                                decoration: BoxDecoration(
                                  color: Colors.red,
                                  borderRadius: BorderRadius.circular(15.0),
                                ),
                                child: const Row(
                                  mainAxisAlignment: MainAxisAlignment.center,
                                  children: [
                                    Icon(
                                      Icons.info_outlined,
                                      color: Colors.white,
                                    ),
                                    Text(
                                      '未识别到文字。',
                                      style: TextStyle(color: Colors.white),
                                    ),
                                  ],
                                ),
                              ),
                              Positioned(
                                  right: 35.0,
                                  bottom: 1,
                                  child: RotatedBox(
                                    quarterTurns: 0,
                                    child: CustomPaint(painter: ArrowShape(arrowColor: Colors.red, arrowSize: 10.0)),
                                  )),
                            ],
                          ),
                          const SizedBox(
                            height: 50.0,
                          ),
                          // 操作项
                          Row(
                            mainAxisAlignment: MainAxisAlignment.spaceBetween,
                            children: [
                              GestureDetector(
                                child: Container(
                                  height: 60.0,
                                  width: 60.0,
                                  decoration: const BoxDecoration(
                                    color: Colors.transparent,
                                  ),
                                  child: const Column(
                                    mainAxisAlignment: MainAxisAlignment.center,
                                    children: [
                                      Icon(
                                        Icons.undo,
                                        color: Colors.white54,
                                      ),
                                      Text(
                                        '取消',
                                        style: TextStyle(color: Colors.white70),
                                      )
                                    ],
                                  ),
                                ),
                                onTap: () {
                                  setState(() {
                                    voicePanelEnable = false;
                                    voiceToTransfer = false;
                                  });
                                },
                              ),
                              GestureDetector(
                                child: Container(
                                  height: 60.0,
                                  width: 100.0,
                                  decoration: const BoxDecoration(
                                    color: Colors.transparent,
                                  ),
                                  child: const Column(
                                    mainAxisAlignment: MainAxisAlignment.center,
                                    children: [
                                      Icon(
                                        Icons.graphic_eq_rounded,
                                        color: Colors.white54,
                                      ),
                                      Text(
                                        '发送原语音',
                                        style: TextStyle(color: Colors.white70),
                                      )
                                    ],
                                  ),
                                ),
                                onTap: () {},
                              ),
                              GestureDetector(
                                child: Container(
                                  height: 60.0,
                                  width: 60.0,
                                  decoration: BoxDecoration(
                                    borderRadius: BorderRadius.circular(50.0),
                                    color: Colors.white12,
                                  ),
                                  child: const Icon(
                                    Icons.check,
                                    color: Colors.white12,
                                  ),
                                ),
                                onTap: () {},
                              ),
                            ],
                          ),
                        ],
                      ),
                    ),
                  ),
                  // 提示文字(操作状态)
                  Positioned(
                    bottom: 120,
                    left: 0,
                    width: MediaQuery.of(context).size.width,
                    child: Visibility(
                      visible: !voiceToTransfer,
                      child: Align(
                        child: Text(
                          voiceTypeMap[voiceType],
                          style: const TextStyle(color: Colors.white70),
                        ),
                      ),
                    ),
                  ),
                  // 背景
                  Align(
                    alignment: Alignment.bottomCenter,
                    child: Visibility(
                      visible: !voiceToTransfer,
                      child: Image.asset('assets/images/voice_bg.webp', width: double.infinity, height: 100.0, fit: BoxFit.fill),
                    ),
                  ),
                  // 背景图标
                  Positioned(
                    bottom: 25,
                    left: 0,
                    width: MediaQuery.of(context).size.width,
                    child: Visibility(
                      visible: !voiceToTransfer,
                      child: const Align(
                        child: Icon(
                          Icons.graphic_eq_rounded,
                          color: Colors.black54,
                        ),
                      ),
                    ),
                  ),
                ],
              ),
            ),
          ),
        )
      ],
    );
  }
}

// 渲染聊天消息公共部分
class RenderChatItem extends StatelessWidget {
  const RenderChatItem({
    super.key,
    required this.data,
    required this.child,
  });
  final V2TimMessage data; // 消息数据
  final Widget? child; // 消息体

  // 设置箭头颜色
  // Color arrowColor(data) {
  //   Color color = Colors.transparent;
  //   if ([8].contains(data.elemType)) {
  //     // 红包箭头颜色
  //     color = const Color(0xFFFFA52F);
  //   } else if ([9].contains(data.elemType)) {
  //     // 位置箭头颜色
  //     color = const Color(0xFFFFFFFF);
  //   } else {
  //     color = !data['isme'] ? const Color(0xFFFFFFFF) : const Color(0xFF9543FF);
  //   }
  //   return color;
  // }

  @override
  Widget build(BuildContext context) {
    String? displayName = (data.friendRemark?.isNotEmpty ?? false)
        ? data.friendRemark
        : (data.nameCard?.isNotEmpty ?? false)
            ? data.nameCard
            : (data.nickName?.isNotEmpty ?? false)
                ? data.nickName
                : '未知昵称';
    return Container(
      margin: const EdgeInsets.only(bottom: 10.0),
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          !(data.isSelf ?? false)
              ? GestureDetector(
                  onTap: () {
                    // 头像点击事件
                    logger.e("点击了头像");
                    Get.toNamed('/vloger', arguments: {'memberId': data.sender});

                    // 你可以在这里处理点击事件，例如打开用户详情页
                  },
                  child: SizedBox(
                    height: 35.0,
                    width: 35.0,
                    child: ClipRRect(
                      borderRadius: const BorderRadius.all(Radius.circular(20.0)),
                      child: NetworkOrAssetImage(imageUrl: data.faceUrl),
                    ),
                  ),
                )
              : const SizedBox.shrink(),
          Expanded(
            child: Padding(
              padding: !(data.isSelf ?? false) ? const EdgeInsets.only(left: 10.0, right: 40.0) : const EdgeInsets.only(left: 40.0, right: 10.0),
              child: Column(
                crossAxisAlignment: !(data.isSelf ?? false) ? CrossAxisAlignment.start : CrossAxisAlignment.end,
                children: [
                  // Text(
                  //   displayName ?? '未知昵称',
                  //   style: const TextStyle(color: Colors.grey, fontSize: 12.0),
                  // ),
                  // const SizedBox(
                  //   height: 3.0,
                  // ),
                  Stack(
                    children: [
                      // 气泡箭头
                      /* Visibility(
                        // 显示箭头(消息+语音+红包+位置)
                        visible: [3, 7, 8, 9].contains(data['contentType']),
                        child: Positioned(
                          left: !data['isme'] ? 1 : null,
                          right: data['isme'] ? 1 : null,
                          top: 20.0,
                          child: RotatedBox(
                            quarterTurns: !data['isme'] ? 1 : -1,
                            child: CustomPaint(painter: ArrowShape(arrowColor: arrowColor(data))),
                          )
                        ),
                      ), */
                      Container(
                        child: child,
                      ),
                    ],
                  ),
                ],
              ),
            ),
          ),
          data.isSelf ?? false
              ? SizedBox(
                  height: 35.0,
                  width: 35.0,
                  child: ClipRRect(
                    borderRadius: const BorderRadius.all(Radius.circular(20.0)),
                    child: NetworkOrAssetImage(imageUrl: data.faceUrl),
                  ),
                )
              : const SizedBox.shrink(),
        ],
      ),
    );
  }
}

// 绘制气泡箭头
class ArrowShape extends CustomPainter {
  ArrowShape({
    required this.arrowColor,
    this.arrowSize = 7,
  });

  final Color arrowColor; // 箭头颜色
  final double arrowSize; // 箭头大小

  @override
  void paint(Canvas canvas, Size size) {
    var paint = Paint()..color = arrowColor;

    var path = Path();
    path.lineTo(-arrowSize, 0);
    path.lineTo(0, arrowSize);
    path.lineTo(arrowSize, 0);
    canvas.drawPath(path, paint);
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return false;
  }
}
