import 'dart:async';

import 'package:equatable/equatable.dart';
import 'package:flutter/foundation.dart';
import 'package:hamlemuhcrm/features/message/model/group_response.dart';
import 'package:hamlemuhcrm/features/message/model/query/req_page_key.dart';
import 'package:hamlemuhcrm/features/message/model/query/req_upload_file.dart';

import '../../../core/base/base_cubit.dart';
import '../../../core/base/base_response.dart';
import '../../../data/repo/message_repository.dart';
import '../model/group_latest_message.dart';
import '../model/group_not_message.dart';
import '../model/group_one_on_one_response.dart';
import '../model/message.dart';
import '../model/query/req_fetch_group.dart';
import '../model/query/req_fetch_message.dart';
import '../model/query/req_multi_group.dart';
import '../model/query/req_one_on_one_group.dart';
import '../model/query/req_seen_update_group.dart';
import '../model/query/req_send_message.dart';
import '../model/query/req_update_group.dart';

part 'message_state.dart';

final class MessageCubit extends BaseCubit<MessageState> {
  final MessageRepository _repository;

  MessageCubit(this._repository) : super(MessageState.initial());

  List<GroupLatestMessage> gelenGorusulenlerListesi = [];
  List<GroupNotMessage> gelenFirmaGorusulmeyenlerListesi = [];
  List<GroupNotMessage> gelenDigerGorusulmeyenlerListesi = [];

  List<String> secilenGrupKullanicilariIdler = [];
  List<String> secilenGrupKullanicilariAdlar = [];

  List<String> secilenGrupYoneticileriIdler = [];
  List<String> secilenGrupYoneticileriAdlar = [];

  /// compute ile çoklu çekirdek üzerinde gelen listeyi alt metotta liste olarak alıcaz
  Future<GroupResponse?> computeFetchGroupList(ReqFetchGroup model) async {
    return await compute(MessageRepository.fetchComputeGroupList, model);
  }

  Future<String> responsePageKey(ReqPageKey model) async {
    final result = await _repository.callPageKeyService(model);

    return result.pagekey ?? '';
  }

  // burada ilk olarak kişinin bağlı olduğu son sohbetler çekilecek
  Future<void> fetchGroupList(ReqFetchGroup model) async {
    emit(state.copyWith(
      status: MessageStatus.loading,
    ));
    try {
      final liste = await computeFetchGroupList(model);
      // Son Hareket Tarihine Göre Sıralama Yaptık
      if (liste != null) {
        liste.gorusulenler
            ?.sort((a, b) => b.sonmesajtarihi!.compareTo(a.sonmesajtarihi!));
        liste.firmaGorusulmeyenler
            ?.sort((a, b) => b.kullaniciId!.compareTo(a.kullaniciId!));
        liste.digerGorusulmeyenler
            ?.sort((a, b) => b.kullaniciId!.compareTo(a.kullaniciId!));
        gelenGorusulenlerListesi = liste.gorusulenler!;

        return emit(state.copyWith(
          status: MessageStatus.loaded,
          gorusulenler: liste.gorusulenler,
          firmaGorusulmeyenler: liste.firmaGorusulmeyenler,
          digerGorusulmeyenler: liste.digerGorusulmeyenler,
        ));
      }

      // gelen null ise mevcut liste kalsın

      emit(state.copyWith(
        status: MessageStatus.loaded,
        gorusulenler: state.gorusulenler,
        firmaGorusulmeyenler: state.firmaGorusulmeyenler,
        digerGorusulmeyenler: state.digerGorusulmeyenler,
      ));
    } catch (e) {
      emit(state.copyWith(
          status: MessageStatus.error,
          errorMessage: 'Veriler Yüklenirken Hata Oluştu'));
    }
  }

  Future<void> searchGroupList(String key, ReqFetchGroup model) async {
    safeEmit(state.copyWith(
      status: MessageStatus.loading,
    ));
    try {
      // önce grupların son halini yeniden çekelim ki aramada eski liste gözükmesin
      await fetchGroupList(model);

      var liste = <GroupLatestMessage>[];
      // ardından güncellenmiş gelenGorusulenlerListesinden keye göre grupları gösterelim
      if (gelenGorusulenlerListesi.isNotEmpty) {
        for (var element in gelenGorusulenlerListesi) {
          if (element.grupAdi!.toLowerCase().contains(key.toLowerCase())) {
            liste.add(element);
          }
        }
      }
      safeEmit(state.copyWith(
        status: MessageStatus.loaded,
        gorusulenler: liste,
      ));
    } catch (e) {
      safeEmit(state.copyWith(
          status: MessageStatus.error,
          errorMessage: 'Veriler Yüklenirken Hata Oluştu'));
    }
  }

  Future<void> fetchMessageList(
    ReqFetchMessage mesajModel,
  ) async {
    safeEmit(state.copyWith(
      status: MessageStatus.loading,
    ));
    try {
      var mesajListe = await _repository
          .fetchMessageList(mesajModel); // fetch message list item
      await _repository
          .lastSeenUpdate(ReqSeenUpdateGroup(
              loginuserid: mesajModel.loginuserid,
              token: mesajModel.token,
              grupUserfirmid: mesajModel.userfirmid,
              grupId: mesajModel.grupId))
          .then((value) async {
        var grupListesi = await _repository.fetchGroupList(ReqFetchGroup(
            loginuserid: mesajModel.loginuserid,
            token: mesajModel.token,
            userfirmid: mesajModel.userfirmid)); // fetch group list item

        grupListesi?.gorusulenler
            ?.sort((a, b) => b.sonmesajtarihi!.compareTo(a.sonmesajtarihi!));

        safeEmit(state.copyWith(
            status: MessageStatus.loaded,
            mesajListesi: mesajListe,
            gorusulenler: grupListesi?.gorusulenler));
      }); // last seen user group updated
    } catch (e) {
      safeEmit(state.copyWith(
          status: MessageStatus.error,
          errorMessage: 'Veriler Yüklenirken Hata Oluştu'));
    }
  }

  Future<void> fetchPaginationMessageList(ReqFetchMessage mesajModel) async {
    if (state.hasReachedMax) return;
    try {
      /// ilk metoda girdiğinde buraya girecek
      if (state.status == MessageStatus.initial) {
        /// servis isteğimizi atalım
        final messages =
            await _repository.fetchPaginationMessageList(mesajModel);

        /// ilk çektiğimiz mesajlar gelecek, lastId '-1' default gönderildi => -1 ilk 10 mesajı getirir / ID yüksekten küçüğe sıralı şekilde
        return emit(state.copyWith(
            status: MessageStatus.loaded,
            mesajListesi: messages,
            hasReachedMax: false));
      }

      /// artık ilk 10 mesaj veya daha
      final messages = await _repository.fetchPaginationMessageList(
          mesajModel, state.mesajListesi.last.mesajId ?? "-1");

      messages.isEmpty
          ? emit(state.copyWith(hasReachedMax: true))
          : emit(state.copyWith(
              status: MessageStatus.loaded,
              mesajListesi: List.of(state.mesajListesi)..addAll(messages)));
    } catch (_) {
      // Hata olduğunda failure durumunu emit ediyorum
      emit(state.copyWith(status: MessageStatus.error));
    }
  }

  Future<void> fetchLastMessageList(ReqFetchMessage mesajModel,
      {String bottomid = "-1"}) async {
    try {
      /// Yüklenme durumuna geçirelim
      emit(state.copyWith(status: MessageStatus.loading));

      /// Yeni mesajlar çekilsin burada first kullanımının sebebi state.mesajListesi'nde ki birinci elemanın en büyük id'li mesaj olması
      final lastMessages = await _repository.fetchLastMessageList(
          mesajModel, state.mesajListesi.first.mesajId ?? "-1");

      /// Son mesajlardan geldikten sonra önceki sayfadaki grup listesi de yenilensin.
      final group = await _repository.fetchGroupList(ReqFetchGroup(
          loginuserid: mesajModel.loginuserid,
          token: mesajModel.token,
          userfirmid: mesajModel.userfirmid));

      /// Aynı zamanda o grupta ki mesajları son görende olmuştur.
      await _repository.lastSeenUpdate(ReqSeenUpdateGroup(
          loginuserid: mesajModel.loginuserid,
          token: mesajModel.token,
          grupUserfirmid: mesajModel.userfirmid,
          grupId: mesajModel.grupId));

      /// Eğer son mesaj var ise insertAll ile çektiğimiz listeyi en başa ekleyelim
      if (lastMessages.isNotEmpty) {
        return emit(state.copyWith(
            status: MessageStatus.loaded,
            mesajListesi: List.of(state.mesajListesi)
              ..insertAll(0, lastMessages),
            gorusulenler: group?.gorusulenler,
            digerGorusulmeyenler: group?.digerGorusulmeyenler,
            firmaGorusulmeyenler: group?.firmaGorusulmeyenler));
      }

      /// Eğer son mesaj yok ise mevcut mesaj listesi kalsın, yine de son çektiğimiz grup listelerini güncelleyelim
      emit(state.copyWith(
          status: MessageStatus.loaded,
          mesajListesi: state.mesajListesi,
          gorusulenler: group?.gorusulenler,
          digerGorusulmeyenler: group?.digerGorusulmeyenler,
          firmaGorusulmeyenler: group?.firmaGorusulmeyenler));
    } catch (_) {
      /// Hata durumunda ekrana haber verelim
      emit(state.copyWith(status: MessageStatus.error));
    }
  }

  Future<void> lastSeenUpdate(ReqSeenUpdateGroup model) async {
    /// Yükleme durumuna geçelim
    emit(state.copyWith(status: MessageStatus.loading));

    /// İş metotudunu çağıralım
    await _repository.lastSeenUpdate(model);

    /// Son grup listesini çekelim
    final group = await _repository.fetchGroupList(ReqFetchGroup(
        loginuserid: model.loginuserid,
        token: model.token,
        userfirmid: model.grupUserfirmid));

    /// Son değerleri alalım ekranı güncelleyelim, yüklendi durumuna status'u geçirelim
    emit(state.copyWith(
        status: MessageStatus.loaded,
        gorusulenler: group?.gorusulenler,
        digerGorusulmeyenler: group?.digerGorusulmeyenler,
        firmaGorusulmeyenler: group?.firmaGorusulmeyenler));
  }

  Future<GroupLatestMessage> makeOneOnOneGroup(ReqOneOnOneGroup model) async {
    GroupCreateResponse grup = await _repository.createOneOnOneGroup(model);
    if (grup.grup != null && grup.success == 1) {
      return grup.grup!;
    }
    return GroupLatestMessage(grupId: "0");
  }

  Future<GroupLatestMessage> createMultiGroup(ReqMultiGroup model) async {
    emit(state.copyWith(status: MessageStatus.initial));
    GroupCreateResponse grup = await _repository.createMultiGroup(model);

    final gelenGruplar = await _repository.fetchGroupList(ReqFetchGroup(
        loginuserid: model.loginuserid,
        token: model.token,
        userfirmid: model.userfirmid));

    if (grup.grup != null && grup.success == 1 && gelenGruplar != null) {
      emit(state.copyWith(
          gorusulenler: gelenGruplar.gorusulenler,
          digerGorusulmeyenler: gelenGruplar.digerGorusulmeyenler,
          firmaGorusulmeyenler: gelenGruplar.firmaGorusulmeyenler,
          status: MessageStatus.loaded));

      return grup.grup!;
    }
    return GroupLatestMessage(
      grupId: "0",
    );
  }

  Future<bool> updateMultiGroup(ReqUpdateGroup model) async {
    emit(state.copyWith(status: MessageStatus.initial));
    BaseResponseModel response = await _repository.updateMultiGroup(model);
    final gelenGruplar = await _repository.fetchGroupList(ReqFetchGroup(
        loginuserid: model.loginuserid,
        token: model.token,
        userfirmid: model.userfirmid));
    if (gelenGruplar == null && response.success != 1) return false;

    emit(state.copyWith(
        gorusulenler: gelenGruplar?.gorusulenler,
        digerGorusulmeyenler: gelenGruplar?.digerGorusulmeyenler,
        firmaGorusulmeyenler: gelenGruplar?.firmaGorusulmeyenler,
        status: MessageStatus.loaded));

    return true;
  }

  Future<String> uploadFile(ReqUploadFile model) async {
    return await _repository.uploadFileToServer(model);
  }

  Future<void> sendMessageToGroup(ReqSendMessage model) async {
    final result = await _repository.sendMessageToGroup(model);
    if (result == null) {
      return emit(state.copyWith(
          status: MessageStatus.error, errorMessage: "Mesaj Gönderilemedi"));
    }
    switch (result.success) {
      case 1:
        return;
      case 0:
      default:
        return emit(state.copyWith(
            status: MessageStatus.error, errorMessage: "Mesaj Gönderilemedi"));
    }
  }
}
