import 'dart:async';
import 'dart:developer' as dev;
import 'dart:io';
import 'dart:math';
import 'package:audio_waveforms/audio_waveforms.dart';
import 'package:flutter/material.dart';
import 'package:flutter_sound/flutter_sound.dart';
import 'package:get/get.dart';
import 'package:taafee_mobile/core/utils/pagination_list.dart';
import 'package:taafee_mobile/core/utils/rx_futures.dart';
import 'package:taafee_mobile/core/utils/utils.dart';
import 'package:taafee_mobile/features/chat/data_layer/model/chat_user.dart';
import 'package:taafee_mobile/features/chat/data_layer/model/room.dart';
import 'package:taafee_mobile/features/chat/data_layer/service/chat_resource.dart'
    as resource;
// import 'package:path_provider/path_provider.dart';
import 'package:rx_future/rx_future.dart';
import 'package:permission_handler/permission_handler.dart';
import '../../../core/errors/custom_exception.dart';
import '../../../core/local_storage/local_storage.dart';
import '../../../core/network/socket/socket.dart';
import '../data_layer/model/message.dart';
import '../data_layer/service/chat_files_source.dart';
import '../data_layer/service/chat_listener.dart';

enum SocketConnectionState { connected, connecting, notConnected, error }

class ChatController extends GetxController {
  //sources
  resource.ChatResource chatResource = resource.ChatResource();

  ChatListener chatListener = ChatListener();

  ChatFilesSource chatFilesSource = ChatFilesSource();

  LocalStorage localStorage = LocalStorage();
  //initialization
  Future<void> init(
      {dynamic Function(MessageModel)? handler,
      required Function(dynamic) onSessionTerminated}) async {
    if (isInitialized) return;
    chatUser = ChatUser(
        id: localStorage.getChatUserId() ?? 0,
        name: localStorage.getUser()!.firstName);
    await socketInit();
    receiveMessagesInRoom();
    receiveMessages(handler: handler);
    listenForMessagesReading();
    listenOnRoomState();
    listenOnSessionTerminated(onSessionTerminated: onSessionTerminated);
  }

  //socket

  SocketIO io = Get.find<SocketIO>();

  bool isInitialized = false;

  Future<void> socketInit() async {
    if (isInitialized) return;
    io.init();
    io.setAuthentication(localStorage.getChatToken() ?? "");
    io.setOnConnect(() {
      connectionState.update((val) {
        connectionState.value = SocketConnectionState.connected;
      });
      connectionState.refresh();
      dev.log("Connected Successfully");
    });
    io.setOnDisconnect(() {
      dev.log("Socket disconnected");
      connectionState.update((val) {
        val = SocketConnectionState.notConnected;
      });
      connectionState.refresh();
    });
    io.setOnConnecting(() {
      connectionState.update((val) {
        val = SocketConnectionState.connecting;
      });
      connectionState.refresh();
      dev.log("Connecting to socket");
    });
    io.setOnConnectionError(() {
      dev.log("Error Connecting to socket");
      connectionState.update((val) {
        val = SocketConnectionState.error;
      });
      connectionState.refresh();
      throw GenericException(
        type: ExceptionType.connectionError,
        errorMessage: "You Have no Internet Connection",
      );
    });

    isInitialized = true;
    await io.connect();
  }

  // user
  ChatUser chatUser = ChatUser.zero();

  /// ------------------- connection -----------///
  RxFuture<void> serverState = RxFuture(null);

  Rx<SocketConnectionState> connectionState =
      SocketConnectionState.notConnected.obs;

  bool get shouldConnect =>
      (connectionState.value == SocketConnectionState.error) |
      (connectionState.value == SocketConnectionState.notConnected);

  Future<void> connectToServer({Function? onSuccess}) async {
    if (!shouldConnect) return;
    serverState.observe((_) async {
      return await io.boot();
    }, onSuccess: ((p0) {
      onSuccess?.call();
    }));
  }

  /// ------------------- Rooms ----------------///
  RxFuture<Pagination<Room>> rooms = RxFuture(Pagination());

  int? get currentRoomId => currentRoom.value?.id;

  ChatUser? get currentChatUser => currentRoom.value!.user;

  Rx<Room?> currentRoom = null.obs;

  //private
  void setCurrentRoom(Room room) {
    currentRoom = room.obs;
    currentRoom.refresh();
  }

  Room? getRoomById(int? id) => id == null
      ? null
      : rooms.result.data.firstWhereOrNull((element) => element.id == id);

  // Future<void> getRooms({int? specificPage}) async {
  //   await connectToServer();
  //   await rooms.observe(
  //     (value) async {
  //       await value!.nextPage(
  //         (currentPage) async {
  //           return chatResource.getRooms(currentPage);
  //         },
  //         place: InsertPlace.end,
  //       );

  //       return value; // there is no way that this would be null, there is a default value in rooms declaration.
  //     },
  //     multipleCallsBehavior: MultipleCallsBehavior.abortNew,
  //   );
  // }

  Future<void> getRooms({String searchQuery = '', int? specificPage}) async {
    await connectToServer();
    if (specificPage != null) {
      rooms.update((val) {
        val!.value.clear();
      });
      rooms.refresh();
    }
    await rooms.observe(
      (value) async {
        await value!.nextPage(
          (currentPage) async {
            return chatResource.getRooms(
                searchQuery: searchQuery,
                currentPage: specificPage ?? currentPage);
          },
          place: InsertPlace.end,
        );

        return value; // there is no way that this would be null, there is a default value in rooms declaration.
      },
      multipleCallsBehavior: MultipleCallsBehavior.abortNew,
    );
  }

  void updateRoom() {
    int index = rooms.result.data
        .indexWhere((element) => (element.id == currentRoomId));
    // rooms = Pagination(
    //     data: rooms.result.data.insert(0, Room.copy(currentRoom.value!)));
    rooms.update((val) {
      if (index == -1) {
        val!.value.data.insert(0, Room.copy(currentRoom.value!));
        index = 0;
      }
      if (currentRoom.value!.messages.data.isNotEmpty) {
        val!.value.data[index].lastMessage =
            currentRoom.value!.messages.data[0];
        val.value.data[index].lastMessageDate =
            currentRoom.value!.messages.data[0].createdAt;
      }
      if (index != 0 &&
          (val!.value.data[index].lastMessageDate.hour == DateTime.now().hour &&
              val.value.data[index].lastMessageDate.day == DateTime.now().day &&
              val.value.data[index].lastMessageDate.month ==
                  DateTime.now().month &&
              val.value.data[index].lastMessageDate.year ==
                  DateTime.now().year)) {
        Room room = val.value.data[index];
        val.value.data.removeAt(index);
        val.value.data.insert(0, room);
      }
    });
    rooms.refresh();
  }

  RxFuture<Room?> createRoomState = RxFuture(null);
  void createRoom(
      {required int chatUserId, void Function(Room?)? onSuccess}) async {
    await createRoomState.observe((value) async {
      return await chatResource.createRoom(id: chatUserId);
    }, onSuccess: (room) async {
      await getRooms();
      Room? roomById = getRoomById(room!.id);
      if (roomById != null) {
        room = roomById;
      }
      currentRoom = room.obs;

      // currentRoom.update((val) {
      //   val = room;
      // });
      // currentRoom.value = room;
      currentRoom.refresh();
      onSuccess?.call(room);
    }, onError: (err) {
      if (err.toString() == 'email_already_exists') {
        // getRooms()
        // get the room that contains two users (chatUserId)
        // setCurrentRoom
        //
      }
    });
  }

  RxFuture<void> blockRoomState = RxFuture(null);
  void blockRoom(
      {void Function()? onSuccess, void Function(Object)? onError}) async {
    blockRoomState.observe((value) async {
      return await chatResource.blockRoom(id: currentRoomId!);
    }, onSuccess: (value) async {
      if (rooms.result.data.isEmpty) {
        await getRooms();
      }
      int index = rooms.result.data
          .indexWhere((element) => element.id == currentRoomId);
      rooms.update((val) {
        val!.value.data[index].state = RoomState.blocked;
      });
      currentRoom.update((val) {
        val!.state = RoomState.blocked;
      });
      currentRoom.refresh();
      rooms.refresh();
      onSuccess?.call();
    }, onError: (err) {
      onError?.call(err);
    });
  }

  RxFuture<void> unblockRoomState = RxFuture(null);
  void unblockRoom(
      {void Function()? onSuccess, void Function(Object)? onError}) async {
    blockRoomState.observe((value) async {
      return await chatResource.unblockRoom(id: currentRoomId!);
    }, onSuccess: (value) {
      int index = rooms.result.data
          .indexWhere((element) => element.id == currentRoomId);
      rooms.update((val) {
        val!.value.data[index].state = RoomState.active;
      });
      currentRoom.update((val) {
        val!.state = RoomState.active;
      });
      currentRoom.refresh();
      rooms.refresh();
      onSuccess?.call();
    }, onError: (err) {
      onError?.call(err);
    });
  }

  void listenOnRoomState() {
    listenOnRoomBlocked();
    listenOnRoomBlocking();
    listenOnRoomUnblocked();
    // chatListener.updatedRoom((roomId, roomStatus) {
    //   if (rooms.result.data.isNotEmpty) {
    //     int index = rooms.result.data
    //         .indexWhere((element) => element.id == currentRoomId);
    //     rooms.update((val) {
    //       val!.value.data[index].state = Room.getRoomStateByString(roomStatus)!;
    //     });
    //     rooms.refresh();
    //     if (currentRoomId == roomId) {
    //       currentRoom.update((val) {
    //         val!.state = Room.getRoomStateByString(roomStatus)!;
    //       });
    //       currentRoom.refresh();
    //     }
    //   }
    // });
  }

  void listenOnRoomUnblocked() {
    chatListener.unblockedRoom((roomId) {
      if (rooms.result.data.isNotEmpty) {
        int index = rooms.result.data
            .indexWhere((element) => element.id == currentRoomId);
        rooms.update((val) {
          val!.value.data[index].state = RoomState.active;
        });
        rooms.refresh();
        if (currentRoomId == roomId) {
          currentRoom.update((val) {
            val!.state = RoomState.active;
          });
          currentRoom.refresh();
        }
      }
    });
  }

  void listenOnRoomBlocked() {
    chatListener.blockedRoom((roomId) {
      if (rooms.result.data.isNotEmpty) {
        int index = rooms.result.data
            .indexWhere((element) => element.id == currentRoomId);
        rooms.update((val) {
          val!.value.data[index].state = RoomState.blocking;
        });
        rooms.refresh();
        if (currentRoomId == roomId) {
          currentRoom.update((val) {
            val!.state = RoomState.blocking;
          });
          currentRoom.refresh();
        }
      }
    });
  }

  void listenOnRoomBlocking() {
    chatListener.blockingRoom((roomId) {
      if (rooms.result.data.isNotEmpty) {
        int index = rooms.result.data
            .indexWhere((element) => element.id == currentRoomId);
        rooms.update((val) {
          val!.value.data[index].state = RoomState.blocked;
        });
        rooms.refresh();
        if (currentRoomId == roomId) {
          currentRoom.update((val) {
            val!.state = RoomState.blocked;
          });
          currentRoom.refresh();
        }
      }
    });
  }

  void listenOnSessionTerminated(
      {required Function(dynamic) onSessionTerminated}) {
    chatListener.termminatedSession(onSessionTerminated);
  }

  //support
  RxFuture<Room?> supportRoomState = RxFuture(null);
  Future<void> checkSupportRoomStatus(
      {void Function(Room?)? onSuccess, void Function(Object)? onError}) async {
    supportRoomState.observe((value) async {
      return await chatResource.checkSupportRoomStatus();
    }, onSuccess: (room) async {
      if (room == null) {
        Room newSupportRoom = await chatResource.createSupportRoom();
        setCurrentRoom(newSupportRoom);
        //creat support room
        //set current room
      } else {
        //set current room
        setCurrentRoom(room);
      }
      onSuccess?.call(currentRoom.value);
    }, onError: (err) {
      onError?.call(err);
    });
  }

  /// ------------- messages -------------- ///

  // getMessages
  RxFutures<void> messagesState = RxFutures();

  Future<void> getCurrentRoomMessages({int? specificPage}) async {
    if (currentRoom.value == null ||
        (currentRoom.value!.messagesStateId != null &&
            messagesState.loading(currentRoom.value!.messagesStateId!))) return;

    String id = messagesState.init(RxFuture(null));

    currentRoom.value!.messagesStateId = id;

    await messagesState.observe(
      id,
      (value) async {
        return await currentRoom.value!.messages.nextPage((currentPage) async {
          return await chatResource.getCurrentRoomMessages(
              roomId: currentRoomId!, page: specificPage ?? currentPage);
        });
      },
      onSuccess: (value) {
        currentRoom.refresh();
      },
      multipleCallsBehavior: MultipleCallsBehavior.abortNew,
    );
  }

  //read Message
  RxFutures<void> readMessageState = RxFutures();
  void readMessage({required int messageId}) async {
    dev.log('i am reading message with id : $messageId');
    String sendingStateId = readMessageState.init(RxFuture(null));
    readMessageState.observe(sendingStateId, (value) async {
      await chatResource.readMessage(messageId: messageId);
    }, onSuccess: (value) {
      int index = currentRoom.value!.messages.data
          .indexWhere((element) => element.id == messageId);
      currentRoom.update((val) {
        val!.messages.data[index].readBy!.ids
            .insert(0, val.messages.data[index].user.id);
      });
      currentRoom.refresh();
    });
  }

  void listenForMessagesReading() {
    chatListener.messagesReaded((messageId, userId) {
      if (currentRoom.value != null &&
          currentRoom.value!.type == RoomType.private) {
        currentRoom.update((val) {
          int index = val!.messages.data
              .indexWhere((element) => element.id == messageId);

          val.messages.data[index].readBy!.ids.insert(0, userId);
        });
        currentRoom.refresh();
      }
    });
  }

  // sendMessages
  RxFutures<MessageModel> sendingMessageState = RxFutures();

  RxBool isMessageLoading(String? sendingMessageStateId) {
    if (sendingMessageStateId != null) {
      return messagesState.loading(sendingMessageStateId).obs;
    } else {
      return false.obs;
    }
  }

  Future<void> sendMessage(MessageModel message,
      {int? roomId, String? filePath, void Function(Object e)? onError}) async {
    if (roomId == null && currentRoom.value == null) {
      throw Exception(
        "You must either provide room id, or select a room to send message",
      );
    }
    message.user = chatUser;
    message.userId = chatUser.id;
    if (shouldConnect) {
      try {
        await io.boot();
        await getCurrentRoomMessages(specificPage: 1);
      } catch (err) {
        onError?.call(err);
      }
    }
    String sendingStateId = sendingMessageState.init(RxFuture(message));

    message.sendingStateId = sendingStateId;

    await sendingMessageState.observe(sendingStateId, (_) async {
      message.sendingStateId = sendingStateId;

      // currentRoom.value!.messages.data.insert(0, MessageModel.copy(message));
      if (message.type != MessageType.voice) {
        currentRoom.update((val) {
          val!.messages.data.insert(0, MessageModel.copy(message));
        });
      }
      if (message.type != MessageType.text) {
        await uploadFile(filePath: filePath!);
        if (uploadFileState.result != null) {
          int id = uploadFileState.result!;
          message.content = "$id";
        } else {
          onError?.call(e);
          currentRoom.update((val) {
            val!.messages.data.removeAt(0);
          });
          return message;
        }
      }
      if (message.type == MessageType.voice) {
        currentRoom.update((val) {
          // message.temporaryFile = null;

          val!.messages.data.insert(0, MessageModel.copy(message));

          val.messages.data[0].content = '${uploadFileState.result}';
          // val.messages.data[0].temporaryFile = null;
        });
        currentRoom.refresh();
      }
      return await chatResource.sendMessage(
          messageModel: message, roomId: currentRoomId!);
    }, onSuccess: (value) {
      currentRoom.update((val) {
        val!.messages.data[0].id = value.id;
        val.messages.data[0].sendingStateId = null;
        val.messages.data[0].content = value.content;
        val.messages.data[0].readBy = value.readBy;
        if (message.type != MessageType.voice) {
          val.messages.data[0].temporaryFile = null;
        }
      });
      rooms.refresh();
    }, onError: (err) {
      currentRoom.update((val) {
        val!.messages.data.removeAt(0);
      });

      onError?.call(err);
    });
  }

  // cancel sending
  void cancelSendingMessage(MessageModel message) {
    if (message.sendingStateId == null ||
        !sendingMessageState.loading(message.sendingStateId!)) return;

    sendingMessageState.cancel(message.sendingStateId!);
  }

  // receive Messages

  void receiveMessagesInRoom() async {
    connectToServer();

    chatListener.receiveMessage((message) {
      currentRoom.update((val) {
        val?.messages.data.insert(0, message);
      });
    });
  }

  void receiveMessages({dynamic Function(MessageModel)? handler}) async {
    connectToServer();
    chatListener.receiveMessage((message) async {
      if (rooms.result.data.isEmpty) {
        await getRooms();
      }
      if (rooms.result.data
              .lastIndexWhere((element) => element.id == message.roomId) ==
          -1) {
        await getRooms();
      }

      int index = rooms.result.data
          .lastIndexWhere((element) => element.id == message.roomId);

      if (index == -1) {
        rooms.update((val) {
          val!.value.data.insert(
              0,
              Room(
                  id: message.roomId,
                  user: message.user,
                  lastMessageDate: message.createdAt));
        });
        index = 0;
      }
      rooms.update((val) {
        val!.value.data[index].lastMessage = message;
      });
      rooms.refresh();
      //assign when user tap .
      // currentRoom.value = rooms.result.data
      //     .firstWhere((element) => (element.id == message.roomId));
      handler?.call(message);
    });
  }

  // upload Files
  RxFuture<int?> uploadFileState = RxFuture(null);
  Future<void> uploadFile({required String filePath}) async {
    await uploadFileState.observe((value) async {
      return await chatFilesSource.uploadFile(
          roomId: currentRoomId!, filePath: filePath);
    });
  }

  // Chat Details scroll controller
  Rx<ScrollController> scrollController = ScrollController().obs;

  void scrollControllerJump() {
    scrollController.update((val) {
      val!.jumpTo(0);
    });
    scrollController.refresh();
  }

  // keyBoard opening detection
  RxBool keyBoardOpened = false.obs;
  void setkeyBoardOpened(bool newValue) {
    keyBoardOpened.value = newValue;
    keyBoardOpened.refresh();
  }

  //reply senario handling
  RxBool isReplying = false.obs;

  void toggleIsReplying() => isReplying.value = !isReplying.value;

  Rx<MessageModel> replyModel = MessageModel.zero().obs;

  void updateReplyModel({
    required MessageModel messageModel,
  }) {
    replyModel.value = messageModel;

    replyModel.refresh();
  }

  //voice message
  FlutterSoundRecorder voiceRecorder = FlutterSoundRecorder();

  File recordFile = File('record.wav');

  bool isRecordReady = false;

  RxBool isRecording = false.obs;

  RxString recordingTime = '00:00'.obs;

  File? audioFile;

  toggleIsRecording() {
    if (isRecording.value == false) {
      recordingTime.value = '00:00';
      recordingTime.refresh();
    }
    isRecording.value = !isRecording.value;
    isRecording.refresh();
  }

  Future<File?> getVoiceFile({required String id}) async {
    return await chatFilesSource.getVoiceFile(id);
  }

  void timer() {
    var startTime = DateTime.now();
    Timer.periodic(const Duration(seconds: 1), (t) {
      var diff = DateTime.now().difference(startTime);
      recordingTime.value =
          '${diff.inHours == 0 ? '' : '${diff.inHours.toString().padLeft(2, "0")}:'}${(diff.inMinutes % 60).floor().toString().padLeft(2, "0")}:${(diff.inSeconds % 60).floor().toString().padLeft(2, '0')}';
      recordingTime.refresh();
      if (!voiceRecorder.isRecording) {
        t.cancel();
      }
    });
  }

  Future initRecorder() async {
    final status = await Permission.microphone.request();
    if (status != PermissionStatus.granted) {
      throw 'dfaf';
    }
    await Permission.storage.request();
    await Permission.manageExternalStorage.request();

    await voiceRecorder.openRecorder();

    isRecordReady = true;

    voiceRecorder.setSubscriptionDuration(const Duration(microseconds: 500));
  }

  Future record() async {
    if (!isRecordReady) return;

    await voiceRecorder.startRecorder(
        toFile: '${Utils.randomString(5)}${Random().nextInt(100000)}');

    timer();
  }

  Future cancelRecording() async {
    recordingTime.value = '00:00';
    recordingTime.refresh();
    await voiceRecorder.stopRecorder();
  }

  Future stopRecording({void Function(Object)? onError}) async {
    recordingTime.value = '00:00';
    recordingTime.refresh();
    if (!isRecordReady) return;

    String? path = await voiceRecorder.stopRecorder();
    audioFile = File(path!);
    await sendMessage(
        MessageModel(
          user: chatUser,
          userId: chatUser.id,
          roomId: currentRoomId!,
          content: '',
          createdAt: DateTime.now(),
          temporaryFile: File(audioFile!.path),
          type: MessageType.voice,
        ),
        filePath: audioFile!.path,
        roomId: currentRoomId, onError: (err) {
      onError?.call(err);
    });
  }

  RxMap<String, File> voiceFiles = <String, File>{}.obs;

  Map<String, Rx<PlayerController>> voicePlayers = {};

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

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

  void addVoiceFile(String id, File file) {
    voiceFiles[id] = file;
    voiceFiles.refresh();
  }

  Rx<PlayerController> getVoicePlayer(String id) {
    if (voicePlayers[id] != null) {
      return voicePlayers[id]!;
    }
    voicePlayers[id] = PlayerController().obs;
    return voicePlayers[id]!;
  }

  void updateIsLoading(String id, bool newValue) {
    isLoadingMap[id] = newValue;
    isLoadingMap.refresh();
  }

  void updateIsPlaying(String id, bool newValue) {
    isPlayingMap[id] = newValue;
    isPlayingMap.refresh();
  }

  void clear() {
    isInitialized = false;
    connectionState = SocketConnectionState.notConnected.obs;
    voiceFiles.clear();
    voicePlayers.clear();
    isPlayingMap.clear();
    isLoadingMap.clear();
    voiceRecorder = FlutterSoundRecorder();
    recordFile = File('record.wav');
    isRecordReady = false;
    isRecording = false.obs;
    recordingTime = '00:00'.obs;
    isReplying = false.obs;
    replyModel = MessageModel.zero().obs;
    keyBoardOpened = false.obs;
    scrollController = ScrollController().obs;
    messagesState.clear();
    rooms = RxFuture(Pagination());
    currentRoom = null.obs;
    io.clearListeners();
  }

  // RxBool isPlaying(String id) {
  //   if (isPlayingMap[id] != null) {
  //     return isPlayingMap[id]!;
  //   }
  //   isPlayingMap[id] = false.obs;
  //   return isPlayingMap[id]!;
  // }

  // RxBool isLoading(String id) {
  //   if (isLoadingMap[id] != null) {
  //     return isLoadingMap[id]!;
  //   }
  //   isLoadingMap[id] = false.obs;
  //   return isLoadingMap[id]!;
  // }
}

//dummy
// RxList<MessageModel> messages = [
//   MessageModel(
//     roomId: 0,
//     userId: 0,
//     content: 'message,hi',
//     createdAt: DateTime.now().toString(),
//     user: ChatUser(id: 0, name: 'name'),
//   ),
//   MessageModel(
//     roomId: 0,
//     userId: 0,
//     content: 'message,hi',
//     user: ChatUser(id: 0, name: 'name'),
//     createdAt: DateTime.now().toString(),
//   ),
//   MessageModel(
//     user: ChatUser(id: 0, name: 'name'),
//     roomId: 0,
//     userId: 0,
//     content: 'message,hi',
//     createdAt: DateTime.now().toString(),
//   ),
//   MessageModel(
//     roomId: 0,
//     user: ChatUser(id: 0, name: 'name'),
//     userId: 0,
//     content: 'message,hi',
//     createdAt: DateTime.now().toString(),
//   ),
//   MessageModel(
//     user: ChatUser(id: 0, name: 'name'),
//     roomId: 0,
//     userId: 0,
//     content: 'message,hi',
//     direction: MessageDirection.received,
//     createdAt: DateTime.now().toString(),
//   ),
//   MessageModel(
//     user: ChatUser(id: 0, name: 'name'),
//     roomId: 0,
//     userId: 0,
//     content: 'message,hi',
//     direction: MessageDirection.received,
//     createdAt: DateTime.now().toString(),
//   ),
//   MessageModel(
//     user: ChatUser(id: 0, name: 'name'),
//     roomId: 0,
//     userId: 0,
//     content: 'message,hi',
//     direction: MessageDirection.received,
//     createdAt: DateTime.now().toString(),
//   ),
//   MessageModel(
//     user: ChatUser(id: 0, name: 'name'),
//     roomId: 0,
//     userId: 0,
//     content: 'message,hi',
//     direction: MessageDirection.received,
//     createdAt: DateTime.now().toString(),
//   ),
//   MessageModel(
//     user: ChatUser(id: 0, name: 'name'),
//     roomId: 0,
//     userId: 0,
//     content: 'message,hi',
//     direction: MessageDirection.received,
//     createdAt: DateTime.now().toString(),
//   ),
//   MessageModel(
//     user: ChatUser(id: 0, name: 'name'),
//     roomId: 0,
//     userId: 0,
//     content: 'message,hi',
//     direction: MessageDirection.received,
//     createdAt: DateTime.now().toString(),
//   ),
//   MessageModel(
//     user: ChatUser(id: 0, name: 'name'),
//     roomId: 0,
//     userId: 0,
//     content: 'message,hi',
//     createdAt: DateTime.now().toString(),
//   ),
//   MessageModel(
//     user: ChatUser(id: 0, name: 'name'),
//     roomId: 0,
//     userId: 0,
//     content: 'message,hi',
//     createdAt: DateTime.now().toString(),
//     direction: MessageDirection.received,
//   ),
//   MessageModel(
//     user: ChatUser(id: 0, name: 'name'),
//     roomId: 0,
//     userId: 0,
//     content: networkImageTest,
//     type: MessageType.image,
//     createdAt: DateTime.now().toString(),
//     direction: MessageDirection.received,
//   ),
//   MessageModel(
//     user: ChatUser(id: 0, name: 'name'),
//     roomId: 0,
//     userId: 0,
//     content: networkImageTest,
//     type: MessageType.image,
//     createdAt: DateTime.now().toString(),
//   ),
//   MessageModel(
//     user: ChatUser(id: 0, name: 'name'),
//     roomId: 0,
//     userId: 0,
//     content: 'message,hi',
//     repliedMessage: MessageModel(
//       user: ChatUser(id: 0, name: 'name'),
//       roomId: 0,
//       userId: 0,
//       content: networkImageTest,
//       type: MessageType.image,
//       createdAt: DateTime.now().toString(),
//       direction: MessageDirection.received,
//     ),
//     createdAt: DateTime.now().toString(),
//   ),
//   MessageModel(
//     user: ChatUser(id: 0, name: 'name'),
//     roomId: 0,
//     userId: 0,
//     content: 'message,hi',
//     repliedMessage: MessageModel(
//       user: ChatUser(id: 0, name: 'name'),
//       roomId: 0,
//       userId: 0,
//       content: 'message,hi',
//       createdAt: DateTime.now().toString(),
//     ),
//     createdAt: DateTime.now().toString(),
//   ),
//   MessageModel(
//     user: ChatUser(id: 0, name: 'name'),
//     roomId: 0,
//     userId: 0,
//     content: 'message,hi',
//     repliedMessage: MessageModel(
//       user: ChatUser(id: 0, name: 'name'),
//       roomId: 0,
//       userId: 0,
//       content: 'message,hi',
//       createdAt: DateTime.now().toString(),
//       direction: MessageDirection.received,
//     ),
//     createdAt: DateTime.now().toString(),
//   ),
// ].obs;
