import 'dart:convert';

import 'package:intl/intl.dart';
import 'package:naim/classes/appdata.dart';
import 'package:naim/classes/assets.dart';

class Message {
  String rnd;
  int userid;
  String description;
  String type;
  DateTime timestamp;
  NAUsers user;
  bool print;

  Message(
      {required this.rnd,
      required this.userid,
      required this.description,
      required this.type,
      required this.user,
      required this.timestamp,
      this.print = false});

  factory Message.fromJson(Map<String, dynamic> pjson) {
    return Message(
        rnd: pjson['rnd'].toString(),
        description: pjson['description'].toString(),
        userid: int.parse(pjson["userid"].toString()),
        type: pjson['type'].toString(),
        user: NAUsers.fromJson(pjson['user']),
        timestamp: DateTime.parse(pjson['timestamp']));
  }

  Map<String, dynamic> toMap() {
    return {
      "rnd": rnd,
      "userid": userid,
      "description": description,
      "type": type,
      "user": user.toMap(),
      "timestamp": DateFormat("yyyy-MM-dd HH:mm:ss").format(timestamp)
    };
  }

  String formatDate() {
    var dt = timestamp;
    var diff = DateTime.now().difference(dt);
    var date = DateFormat('MMM d, ').format(dt) + DateFormat('jm').format(dt);
    var date2 =
        DateFormat('MMM d, y ').format(dt) + DateFormat('jm').format(dt);
    var date3 = DateFormat('EEE,').format(dt);

    if (diff.inDays >= 365) {
      var i = (diff.inDays / 365).round();
      if (i > 1) {
        date = i.toString() + " Years ago " + date2;
      } else {
        date = i.toString() + " Year ago " + date2;
      }
    } else if (diff.inDays > 30 && diff.inDays < 365) {
      var i = (diff.inDays / 30).round();
      if (i > 1) {
        date = i.toString() + " Months ago " + date;
      } else {
        date = i.toString() + " Month ago " + date;
      }
    } else if (diff.inDays > 6 && diff.inDays < 30) {
      var i = (diff.inDays / 7).round();
      if (i > 1) {
        date = i.toString() + " Weeks ago " + date;
      }
    } else if (diff.inDays > 0 && diff.inDays < 7) {
      var i = (diff.inDays).round();

      date = date3 + " " + DateFormat('jm').format(dt);
    } else if (diff.inHours > 0 && diff.inHours < 24) {
      var i = (diff.inHours).round();
      if (dt.day != DateTime.now().day) {
        date = "Yesterday, " + DateFormat('jm').format(dt);
      } else {
        date = DateFormat('jm').format(dt);
      }
    } else {
      var i = (diff.inMinutes).round();
      if (i > 1) {
        date = i.toString() + " Minutes ago";
      } else {
        date = i.toString() + " Minute ago";
      }
    }
    return date;
  }

  static List<Message> parseMessages(String str) {
    var msgs = json.decode(str);
    return List<Message>.from(msgs.map((book) {
      return Message.fromJson(book);
    }).toList());
  }

  void sendMessage(bool isGroup, int _to) {
    if (appData.constat != "closed") {
      appData.channel!.sink.add(json.encode({
        "type": "new_message",
        "to": _to,
        "is_group": isGroup ? 1 : 0,
        "from": int.parse(appData.dbUser["id"].toString()),
        "token": appData.dbUser['token'],
        "data": toMap()
      }));
    }
  }

  String getJSON(bool isGroup, int _to) {
    return json.encode({
      "type": "new_message",
      "to": _to,
      "is_group": isGroup ? 1 : 0,
      "from": int.parse(appData.dbUser["id"].toString()),
      "token": appData.dbUser['token'],
      "data": toMap()
    });
  }

  @override
  bool operator ==(other) {
    return other is Message &&
        other.runtimeType == runtimeType &&
        rnd == other.rnd;
  }

  bool operator >(other) {
    return other is Message &&
        other.runtimeType == runtimeType &&
        timestamp.isAfter(other.timestamp);
  }

  bool operator >=(other) {
    return other is Message &&
        other.runtimeType == runtimeType &&
        (timestamp.isAfter(other.timestamp) ||
            timestamp.isAtSameMomentAs(other.timestamp));
  }

  bool operator <=(other) {
    return other is Message &&
        other.runtimeType == runtimeType &&
        (timestamp.isBefore(other.timestamp) ||
            timestamp.isAtSameMomentAs(other.timestamp));
  }

  bool operator <(other) {
    return other is Message &&
        other.runtimeType == runtimeType &&
        timestamp.isBefore(other.timestamp);
  }

  @override
  // TODO: implement hashCode
  int get hashCode => super.hashCode;
}

class MainMessage {
  int id;
  late List<Message>? messages = [];
  int fromId;
  int toId;
  bool isGroup;
  DateTime createdAt;
  DateTime updatedAt;
  MainMessage(
      {required this.id,
      required this.fromId,
      required this.toId,
      required this.isGroup,
      this.messages,
      required this.createdAt,
      required this.updatedAt});

  factory MainMessage.fromJson(Map<String, dynamic> pjson) {
    return MainMessage(
        id: int.parse(pjson['id'].toString()),
        fromId: int.parse(pjson['from_id'].toString()),
        toId: int.parse(pjson['to_id'].toString()),
        messages: Message.parseMessages(pjson['messages'].toString()),
        isGroup: int.parse(pjson['is_group'].toString()) == 1 ? true : false,
        createdAt: DateTime.parse(pjson['created_at'].toString()),
        updatedAt: DateTime.parse(pjson['created_at'].toString()));
  }
}

class MessageKey {
  int id;
  int messageId;
  String messageKey;
  bool isGroup;

  MessageKey(
      {required this.id,
      required this.messageId,
      required this.messageKey,
      required this.isGroup});

  factory MessageKey.fromJson(Map<String, dynamic> pjson) {
    return MessageKey(
        id: int.parse(pjson['id'].toString()),
        messageId: int.parse(pjson['messageId'].toString()),
        messageKey: pjson['messageKey'].toString(),
        isGroup: int.parse(pjson['isGroup'].toString()) == 1 ? true : false);
  }
}
