import 'package:get/get.dart';
import 'package:taafee_mobile/core/utils/utils.dart';

import 'package:rx_future/rx_future.dart';

// class Utils {
//
// }

class RxFutures<T> extends Rx<Map<String, RxFuture<T>>> {
  RxFutures() : super({});

  // @getters
  Map<String, RxFuture<T>> get futures => value;

  bool get allLoading {
    bool result = true;
    value.forEach((key, value) {
      result &= value.loading;
    });
    return result;
  }

  bool get anyLoading {
    bool result = false;
    value.forEach((key, value) {
      result |= value.loading;
    });
    return result;
  }

  int get loadingCounts {
    int count = 0;

    value.forEach((key, value) {
      if (value.loading) count++;
    });

    return count;
  }

  int get length => value.length;

  double get loadingPercentage => loadingCounts / length;

  RxFuture<T> _getFuture(String id) => value[id]!;

  T? result(String id) => value[id]!.result;

  Object? error(String id) => value[id]!.error;

  bool loading(String id) => value[id]!.loading;

  bool hasError(String id) => value[id]!.hasError;

  bool isStable(String id) => value[id]!.isStable;

  String init(RxFuture<T> future) {
    String id = Utils.randomString();

    if (value.containsKey(id)) return init(future);

    value[id] = future;

    return id;
  }

  Future<void> observe(
    String id,
    Future<T> Function(T?) callback, {
    void Function(T)? onSuccess,
    void Function(Object)? onError,
    void Function()? onMultipleCalls,
    void Function()? onCancel,
    MultipleCallsBehavior multipleCallsBehavior =
        MultipleCallsBehavior.abortNew,
  }) async {
    RxFuture<T> future = _getFuture(id);

    update((val) {});

    future.observe(
      callback,
      onSuccess: (value) {
        update((val) {});
        onSuccess?.call(value);
      },
      onError: (error) {
        update((val) {});
        onError?.call(error);
      },
      onCancel: () {
        update((val) {});
        onCancel?.call();
      },
      onMultipleCalls: onMultipleCalls,
      multipleCallsBehavior: multipleCallsBehavior,
    );
  }

  void remove(String id) {
    value[id]?.cancel();
    value.remove(id);
  }

  void cancel(String id) {
    value[id]?.cancel();
  }

  void cancelAll() {
    value.forEach((key, value) {
      value.cancel();
    });
    update((val) {});
  }

  void clear({bool cancel = true, bool stableOnly = false}) {
    if (cancel && !stableOnly) cancelAll();

    if (stableOnly) return value.removeWhere((key, value) => value.isStable);

    value.clear();

    update((val) {});
  }
}
