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

import 'chat_user.dart';
import 'read_by.dart';

class MessageModel {
  int? id;
  MessageType type;
  String content;
  MessageDirection direction;
  MessageModel? repliedMessage;
  DateTime createdAt;
  DateTime? updatedAt;
  int? userId;
  int roomId;
  ReadBy? readBy;
  ChatUser user;
  File? temporaryFile;
  String? sendingStateId;

  // @constructors
  MessageModel({
    this.id,
    this.readBy,
    this.updatedAt,
    required this.user,
    this.userId,
    required this.roomId,
    this.type = MessageType.text,
    this.direction = MessageDirection.sent,
    required this.content,
    this.repliedMessage,
    required this.createdAt,
    this.temporaryFile,
    this.sendingStateId,
  });

  factory MessageModel.zero() => MessageModel(
        content: "",
        createdAt: DateTime.now(),
        user: const ChatUser(id: 0, name: 'name'),
        userId: 0,
        roomId: 0,
        //sender: const ChatUser(id: '0', name: '')
      );
  factory MessageModel.copy(MessageModel messageModel) => MessageModel(
        content: messageModel.content,
        createdAt: messageModel.createdAt,
        id: messageModel.id,
        readBy: messageModel.readBy,
        roomId: messageModel.roomId,
        type: messageModel.type,
        userId: messageModel.userId,
        direction: messageModel.direction,
        temporaryFile: messageModel.temporaryFile,
        repliedMessage: messageModel.repliedMessage,
        user: messageModel.user,
        sendingStateId: messageModel.sendingStateId,
      );
  factory MessageModel.fromJson(Map<String, dynamic> jsonMap,
          {int? userId, int? roomId}) =>
      MessageModel(
        id: jsonMap['id'],
        roomId: roomId ?? jsonMap['roomId'] ?? jsonMap['room']['id'],
        content: jsonMap['content'],
        userId: userId ?? jsonMap["userId"],
        repliedMessage: (jsonMap["repliedMessage"] != null)
            ? MessageModel.fromJson(jsonDecode(jsonMap["repliedMessage"]),
                roomId: jsonMap['roomId'] ?? jsonMap['room']['id'],
                userId: jsonMap["userId"] ?? jsonMap['user']['id'])
            : null,
        readBy: (jsonMap['readBy'] != null)
            ? ReadBy.fromJson(jsonMap['readBy'])
            : null,
        user: (jsonMap['User'] != null)
            ? ChatUser.fromJson(jsonMap['User'])
            : ((jsonMap['user'] != null)
                ? ChatUser.fromJson(jsonMap['user'])
                : const ChatUser(id: 0, name: 'name')),
        createdAt: DateTime.parse(jsonMap['createdAt']).toLocal(),
        updatedAt: (jsonMap['updatedAt'] != null)
            ? DateTime.parse(jsonMap['updatedAt']).toLocal()
            : DateTime.parse(jsonMap['createdAt']).toLocal(),
        type: getMessageType(jsonMap["type"]),
      );

  toJson() => {
        "type": type.messageTypeString,
        "content": content,
        if (repliedMessage != null) "repliedMessage": repliedMessage!.id,
      };
  static List<Map<String, dynamic>> toJsonList(
      List<MessageModel> messagesList) {
    List<Map<String, dynamic>> jsonList = [];
    // ignore: avoid_function_literals_in_foreach_calls
    messagesList.forEach((element) {
      jsonList.add(element.toJson());
    });
    return jsonList;
  }

  static List<MessageModel> fromJsonList(List jsonList) {
    List<MessageModel> messages = [];
    // ignore: avoid_function_literals_in_foreach_calls
    jsonList.forEach((element) {
      messages.add(MessageModel.fromJson(element));
    });
    return messages;
  }

  // @getters
  bool get isReply => repliedMessage != null;
}

enum MessageType { text, image, voice }

MessageType getMessageType(String key) {
  switch (key) {
    case "image":
      return MessageType.image;
    case "voice":
      return MessageType.voice;
  }
  return MessageType.text;
}

extension MyStringExtension on MessageType {
  String get messageTypeString {
    switch (this) {
      case MessageType.image:
        return 'image';
      case MessageType.voice:
        return 'voice';
      case MessageType.text:
        return 'text';
    }
  }
}

enum MessageDirection { received, sent }
