import 'dart:async';

import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:farm_tpf/custom_model/NotificationDTO.dart';
import 'package:farm_tpf/custom_model/NotificationObjectDTO.dart';
import 'package:farm_tpf/custom_model/UpdateNoti.dart';
import 'package:farm_tpf/data/api/app_exception.dart';
import 'package:farm_tpf/data/repository/repository.dart';
import 'package:farm_tpf/utils/const_string.dart';
import 'package:meta/meta.dart';

part 'noti_event.dart';
part 'noti_state.dart';

class NotiBloc extends Bloc<NotiEvent, NotiState> {
  final Repository repository;
  NotiBloc({required this.repository}) : super(NotiInitial());
  static int pageSize = 20;

  @override
  Stream<NotiState> mapEventToState(
    NotiEvent event,
  ) async* {
    if (event is DataFetched && !(state is NotiSuccess && (state as NotiSuccess).hasReachedMax)) {
      try {
        if (state is NotiInitial) {
          yield NotiLoadding();
          final response = await repository.getNotifications(page: 0, size: pageSize);
          var items = <NotificationDTO>[];
          response.notificationDTO?.forEach((e) => items.add(NotificationDTO.clone(e)));
          yield NotiSuccess(
              unread: response.numberUnreadTotal,
              read: response.numberReadTotal,
              items: items,
              page: 0,
              hasReachedMax: (response.notificationDTO?.length ?? 0) < pageSize ? true : false);
        }
        if (state is NotiSuccess) {
          final currentState = state as NotiSuccess;
          var page = currentState.page + 1;
          final response = await repository.getNotifications(page: page, size: pageSize);
          yield (response.notificationDTO ?? <NotificationDTO>[]).isEmpty
              ? currentState.copyWith(hasReachedMax: true)
              : NotiSuccess(
                  unread: response.numberUnreadTotal,
                  read: response.numberReadTotal,
                  items: currentState.items + (response.notificationDTO ?? <NotificationDTO>[]),
                  page: currentState.page + 1,
                  hasReachedMax: false);
        }
      } catch (e) {
        yield NotiFailure(errorString: AppException.handleError(e));
      }
    }
    if (event is OnRefresh) {
      yield NotiLoadding();
      try {
        final response = await repository.getNotifications(page: 0, size: pageSize);
        var items = <NotificationDTO>[];
        response.notificationDTO?.forEach((e) => items.add(NotificationDTO.clone(e)));
        yield NotiSuccess(
            unread: response.numberUnreadTotal,
            read: response.numberReadTotal,
            items: items,
            page: 0,
            hasReachedMax: (response.notificationDTO ?? <NotificationDTO>[]).length < pageSize ? true : false);
      } catch (e) {
        yield NotiFailure(errorString: AppException.handleError(e));
      }
    } else if (event is OnRefreshFromNotification) {
      try {
        final response = await repository.getNotifications(page: 0, size: pageSize);
        var items = <NotificationDTO>[];
        response.notificationDTO?.forEach((e) => items.add(NotificationDTO.clone(e)));
        yield NotiSuccess(
            unread: response.numberUnreadTotal,
            read: response.numberReadTotal,
            items: items,
            page: 0,
            hasReachedMax: (response.notificationDTO ?? <NotificationDTO>[]).length < pageSize ? true : false);
      } catch (e) {
        yield NotiFailure(errorString: AppException.handleError(e));
      }
    }

    if (event is OnUpdate) {
      yield NotiLoadding();
      try {
        //Change status notification if mark read
        if (event.currentItemId != null) {
          var updateNoti = UpdateNoti()
            ..id = event.currentItemId ?? -1
            ..isRead = 1;
          await repository.updateNoti(updateNoti);
        }

        yield NotiSuccess(
            unread: event.unread, read: event.read, items: event.currentItems, page: event.currentPage, hasReachedMax: event.hasReachedMax);
      } catch (e) {
        yield NotiFailure(errorString: exception_common);
      }
    } else if (event is MarkAllNotificationUpdate) {
      yield NotiLoadding();
      try {
        await repository.updateAllNotification(event.status);
        final response = await repository.getNotifications(page: 0, size: pageSize);
        var items = <NotificationDTO>[];
        response.notificationDTO?.forEach((e) => items.add(NotificationDTO.clone(e)));
        yield NotiSuccess(
            unread: response.numberUnreadTotal,
            read: response.numberReadTotal,
            items: items,
            page: 0,
            hasReachedMax: (response.notificationDTO ?? <NotificationDTO>[]).length < pageSize ? true : false);
      } catch (e) {
        yield NotiFailure(errorString: AppException.handleError(e));
      }
    } else if (event is ReceiveDataFromSocket) {
      var updatedItems = <NotificationDTO>[];
      event.updatedItemObject.notificationDTO?.forEach((e) {
        updatedItems.add(NotificationDTO.clone(e));
      });

      event.currentItems.forEach((e) {
        updatedItems.add(NotificationDTO.clone(e));
      });
      yield NotiSuccess(
          unread: event.updatedItemObject.numberUnreadTotal,
          read: event.updatedItemObject.numberReadTotal,
          items: updatedItems,
          page: event.page,
          hasReachedMax: updatedItems.length < pageSize ? true : false);
    }
  }
}
