import 'dart:convert';
import 'dart:io';

import 'package:flutter/material.dart';

import 'package:hive_flutter/hive_flutter.dart';
import 'package:image_picker/image_picker.dart';
import 'package:badges/badges.dart' as badges;

import 'package:together_mobile/common/constants.dart';
import 'package:together_mobile/database/box_type.dart';
import 'package:together_mobile/models/contact_model.dart';
import 'package:together_mobile/models/init_get_it.dart';
import 'package:together_mobile/models/user_model.dart';
import 'package:together_mobile/models/websocket_model.dart';
import 'package:together_mobile/utils/app_dir.dart';
import 'package:together_mobile/utils/format_datetime.dart';
import 'package:together_mobile/utils/ws_receive_callback.dart';
import 'input_icon_button.dart';

class MessageInputBox extends StatefulWidget {
  const MessageInputBox({
    super.key,
    required this.chatType,
    required this.contactId,
    required this.scrollController,
  });

  final int chatType;
  final String contactId;
  final ScrollController scrollController;

  @override
  State<MessageInputBox> createState() => _MessageInputBoxState();
}

class _MessageInputBoxState extends State<MessageInputBox> {
  final TextEditingController _controller = TextEditingController();
  final ImagePicker _picker = ImagePicker();
  bool _hasMsg = false;

  late Box<ChatSetting> _chatSettingBox;
  late Box<MessageT> _messageTBox;

  List<XFile> _imageFileList = [];

  @override
  void initState() {
    super.initState();
    _chatSettingBox = Hive.box<ChatSetting>('chat_setting');
    _messageTBox = Hive.box<MessageT>('message_${widget.contactId}');
  }

  @override
  void dispose() {
    super.dispose();
    _controller.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      decoration: BoxDecoration(
        boxShadow: [
          BoxShadow(
            color: kPrimaryColor.withOpacity(0.5),
            blurRadius: 30,
            // Shadow spared from the edge of the container
            blurStyle: BlurStyle.outer,
          ),
        ],
      ),
      padding: const EdgeInsets.only(top: 6),
      child: Column(
        children: [
          Row(
            crossAxisAlignment: CrossAxisAlignment.end,
            children: [
              const SizedBox(
                width: 10,
              ),
              Expanded(
                child: Container(
                  padding: const EdgeInsets.all(10),
                  constraints: const BoxConstraints(maxHeight: 120),
                  decoration: BoxDecoration(
                    borderRadius: BorderRadius.circular(10),
                    // Container color will be imply to its child
                    color: Theme.of(context).brightness == Brightness.dark
                        ? const Color.fromARGB(255, 61, 61, 61)
                        : kPrimaryColor.withOpacity(0.2),
                  ),
                  child: TextField(
                    onChanged: (value) {
                      if (value.isNotEmpty) {
                        setState(() {
                          _hasMsg = true;
                        });
                      } else {
                        if (_imageFileList.isEmpty) {
                          setState(() {
                            _hasMsg = false;
                          });
                        }
                      }
                    },
                    minLines: null,
                    maxLines: null,
                    controller: _controller,
                    decoration: const InputDecoration(
                      isCollapsed: true,
                      border: UnderlineInputBorder(
                        borderSide: BorderSide.none,
                      ),
                    ),
                  ),
                ),
              ),
              const SizedBox(
                width: 10,
              ),
              FilledButton(
                onPressed: () {
                  _sendMsg();
                },
                style: FilledButton.styleFrom(
                  padding: const EdgeInsets.all(0),
                  tapTargetSize: MaterialTapTargetSize.shrinkWrap,
                  backgroundColor:
                      _hasMsg ? kPrimaryColor : kPrimaryColor.withAlpha(50),
                ),
                child: const Text(
                  '发送',
                  style: TextStyle(
                    fontSize: 16,
                  ),
                ),
              ),
              const SizedBox(
                width: 10,
              ),
            ],
          ),
          Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: [
              InputIconButton(
                onPressed: () {},
                icon: const Icon(Icons.mic),
              ),
              InputIconButton(
                onPressed: () {},
                icon: const Icon(Icons.call),
              ),
              badges.Badge(
                showBadge: _imageFileList.isNotEmpty,
                badgeStyle: const badges.BadgeStyle(
                  badgeColor: kSecondaryColor,
                  elevation: 12,
                ),
                badgeContent: Text(_imageFileList.length.toString()),
                position: badges.BadgePosition.topEnd(top: 0, end: 0),
                child: InputIconButton(
                  onPressed: () {
                    _pickImages(context);
                  },
                  icon: const Icon(Icons.insert_photo),
                ),
              ),
              InputIconButton(
                onPressed: () {},
                icon: const Icon(Icons.emoji_emotions),
              ),
              InputIconButton(
                onPressed: () {},
                icon: const Icon(Icons.add_box_rounded),
              ),
            ],
          ),
        ],
      ),
    );
  }

  void _pickImages(BuildContext context) async {
    try {
      List<XFile> pickedImages = await _picker.pickMultiImage();
      if (pickedImages.isNotEmpty) {
        setState(() {
          _imageFileList = pickedImages;
          _hasMsg = true;
        });
      } else {
        setState(() {
          _imageFileList = [];
        });
        if (_controller.text.isEmpty) {
          setState(() {
            _hasMsg = false;
          });
        }
      }
    } catch (e) {
      print('Error when pick image: $e');
    }
  }

  void _sendMsg() async {
    if (!_hasMsg) {
      return;
    }

    DateTime now = DateTime.now();
    bool isShowTime = _isShowTime(now);
    String senderId = getIt.get<UserAccount>().id;
    String text = _controller.text;
    String type = 'text/multipart';
    List<String> attachments = [];
    Box<AttachmentProgress> apsBox = Hive.box('attachment_send');

    var chatSetting = _chatSettingBox.get(widget.contactId);
    if (chatSetting == null) {
      _chatSettingBox.put(
        widget.contactId,
        ChatSetting(
          widget.contactId,
          widget.chatType,
          false,
          true,
          false,
          now,
          0,
        ),
      );
    } else {
      chatSetting.latestDateTime = now;
      chatSetting.unreadCount = 0;
      chatSetting.isOpen = true;
      _chatSettingBox.put(widget.contactId, chatSetting);
    }

    String dirTime = formatDirTime(now);
    String baseImageDir = getIt.get<UserProfile>().baseImageDir;

    if (_imageFileList.isNotEmpty) {
      final dir = Directory('$baseImageDir/$dirTime');

      if (!(await dir.exists())) {
        await dir.create(recursive: true);
      }

      for (var i = 0; i < _imageFileList.length; i++) {
        String filename = '$dirTime/${getRandomFilename()}';
        int totalChunkNum =
            ((await _imageFileList[i].length()) / chunkSize).ceil();

        attachments.add(filename);
        apsBox.put(
          filename,
          AttachmentProgress(0, totalChunkNum, 0, true, false),
        );

        await _imageFileList[i].saveTo('$baseImageDir/${attachments[i]}');
      }
    }

    final msgId = formatMsgIDFromTime(now);

    _messageTBox.add(
      MessageT(msgId, senderId, text, type, now, isShowTime, attachments),
    );

    Box<int> msgIndexBox =
        await Hive.openBox<int>('msg_index_${widget.contactId}');
    msgIndexBox.put(msgId, _messageTBox.length - 1);

    Future.delayed(
      const Duration(milliseconds: 50),
      () => widget.scrollController.animateTo(
        0,
        duration: const Duration(milliseconds: 500),
        curve: Curves.linear,
      ),
    );

    final msg = {
      'type': 'text/multipart',
      'msgId': msgId,
      'senderId': senderId,
      'text': text,
      'attachments': attachments,
      'dateTime': now.toString(),
      'isShowTime': isShowTime,
    };

    if (widget.chatType == 0) {
      msg['event'] = 'friend-chat-msg';
      msg['receiverId'] = widget.contactId;
      getIt.get<WebSocketManager>().channel.sink.add(json.encode(msg));
    } else {
      List<String> receiverIds = getIt
          .get<ContactAccountProfile>()
          .groupChats[widget.contactId]!
          .members;

      receiverIds.remove(senderId);
      msg['event'] = 'group-chat-msg';
      msg['groupChatId'] = widget.contactId;
      msg['receiverIds'] = receiverIds;
      msg['nickname'] = getIt.get<UserProfile>().nickname;
      msg['remarkInGroupChat'] =
          getIt.get<Contact>().groupChats[widget.contactId]!.remarkInGroupChat;
      msg['avatar'] = getIt.get<UserProfile>().avatar;
      getIt.get<WebSocketManager>().channel.sink.add(json.encode(msg));
    }

    _controller.text = '';
    setState(() {
      _imageFileList.clear();
      _imageFileList = [];
      _hasMsg = false;
    });
  }

  bool _isShowTime(DateTime now) {
    int messageCount = _messageTBox.length;

    if (messageCount == 0) {
      return true;
    } else {
      MessageT? message = _messageTBox.getAt(messageCount - 1);
      DateTime lastTime = message!.dateTime;
      int differenceInMinutes = now.difference(lastTime).inMinutes;
      return differenceInMinutes > 8 ? true : false;
    }
  }
}