import 'dart:async';

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:fcs/data/services/services.dart';
import 'package:fcs/domain/constants.dart';
import 'package:fcs/domain/vo/message.dart';
import 'package:fcs/pages/main/model/base_model.dart';
import 'package:logging/logging.dart';

class MessageModel extends BaseModel {
  final log = Logger('MessageModel');

  List<Message> messages = [];

  @override
  logout() async {
    if (listener != null) await listener!.cancel();
    messages = [];
  }

  late Query query;
  DocumentSnapshot? prevSnap;
  late bool isEnded;
  late bool isLoading;
  String? userID;
  StreamSubscription<QuerySnapshot>? listener;

  static const int rowPerLoad = 20;
  void initQuery(String? userID) {
    if (userID == null) return;
    this.messages = [];
    this.userID = userID;
    this.prevSnap = null;
    query = FirebaseFirestore.instance
        .collection("$user_collection/$userID/$messages_collection")
        .orderBy('date', descending: true);
    load();
  }

  Future<void> load() async {
    if (prevSnap == null) return;
    Query _query =
        prevSnap != null ? query.startAfterDocument(prevSnap!) : query;
    QuerySnapshot snapshot =
        await _query.limit(rowPerLoad).get(GetOptions(source: Source.server));

    int count = snapshot.docs.length;
    isEnded = count < rowPerLoad;
    prevSnap = count > 0 ? snapshot.docs[count - 1] : prevSnap;

    snapshot.docs.forEach((e) {
      messages.add(Message.fromMap(e.data() as Map<String, dynamic>, e.id));
      if (messages.length == 1) {
        _initListener(e);
      }
    });
    notifyListeners();
  }

  void _initListener(DocumentSnapshot snap) {
    if (listener != null) listener!.cancel();

    listener = FirebaseFirestore.instance
        .collection("$user_collection/$userID/$messages_collection")
        .endBeforeDocument(snap)
        .orderBy('date', descending: true)
        .snapshots(includeMetadataChanges: true)
        .listen((qs) {
      qs.docChanges.forEach((c) {
        switch (c.type) {
          case DocumentChangeType.added:
            log.info("added!! $c");
            messages.insert(
                0,
                Message.fromMap(
                    c.doc.data() as Map<String, dynamic>, c.doc.id));
            notifyListeners();
            break;
          case DocumentChangeType.modified:
            log.info("modified!! $c");
            break;
          default:
        }
      });
    });
  }

  Future<void> sendMessage(String msg, String receiverID) {
    Message message = Message(message: msg, receiverID: receiverID);
    return Services.instance.commonService.sendMessage(message);
  }

  Future<void> seenMessages(String ownerID, bool seenByOwner) {
    return Services.instance.commonService.seenMessage(ownerID, seenByOwner);
  }
}
