import 'dart:async';

import 'package:flutter/widgets.dart';

import 'async_typeof.dart';
import 'cancel_future.dart';

class AsyncUtil {
  AsyncUtil._();

  static CancelableFuture<T> retryWithExponentialBackoff<T>(
      FutureCallback<T> callback, int maxRetry, Predicate<dynamic> predicate) {
    const Duration initialInterval = Duration(seconds: 1);
    int retryCount = 0;
    Timer? timer;

    void attempt(Completer<T> completer) {
      callback().then((value) {
        if (!completer.isCompleted) {
          completer.complete(value);
        }
      }).catchError((error) {
        if (retryCount < maxRetry && predicate(error)) {
          retryCount++;
          Duration nextInterval = initialInterval * (1 << (retryCount - 1));
          timer = Timer(nextInterval, () => attempt(completer));
        } else {
          if (!completer.isCompleted) {
            completer.completeError(error);
          }
        }
      });
    }

    return CancelableFuture<T>((completer) {
      attempt(completer);
    }, () {
      timer?.cancel();
    });
  }

  static CancelableFuture<T> retryWhen<T>(FutureCallback<T> callback,
      int maxRetry, Duration interval, Predicate<dynamic> predicate,
      [Duration? timeout]) {
    int retryCount = 0;
    Timer? timer;
    Timer? timeoutTimer;

    void attempt(Completer<T> completer) {
      callback().then((value) {
        if (!completer.isCompleted) {
          completer.complete(value);
        }
      }).catchError((error) {
        if ((maxRetry <= 0 || retryCount < maxRetry) && predicate(error)) {
          retryCount++;
          timer = Timer(interval, () => attempt(completer));
        } else {
          if (!completer.isCompleted) {
            completer.completeError(error);
          }
        }
      });
    }

    return CancelableFuture<T>((completer) {
      if (timeout != null) {
        timeoutTimer = Timer(timeout, () {
          if (!completer.isCompleted) {
            completer.completeError(TimeoutException('Operation timed out'));
          }
        });
      }
      attempt(completer);
    }, () {
      timer?.cancel();
      timeoutTimer?.cancel();
    });
  }

  static CancelableFuture<T> retry<T>(FutureCallback<T> callback, int maxRetry,
      Duration interval, [Duration? timeout]) {
    return retryWhen(callback, maxRetry, interval, (error) => true, timeout);
  }

  static CancelableFuture<T> delay<T>(
      FutureCallback<T> callback, Duration interval) {
    Timer? timer;

    return CancelableFuture<T>((completer) {
      timer = Timer(interval, () {
        callback().then((value) {
          if (!completer.isCompleted) {
            completer.complete(value);
          }
        }).catchError((error) {
          if (!completer.isCompleted) {
            completer.completeError(error);
          }
        });
      });
    }, () {
      timer?.cancel();
    });
  }

  ///实际delay第一次执行的时间为delay+interval
  static CancelableFuture<T> interval<T>(FutureCallback<T> callback,
      Duration delay, Duration interval, int times) {
    Timer? timer;
    Timer? delayTimer;
    int counter = 0;

    void tick(Completer<T> completer) {
      if (counter < times) {
        callback().then((value) {
          if (!completer.isCompleted) {
            completer.complete(value);
          }
        }).catchError((error) {
          if (!completer.isCompleted) {
            completer.completeError(error);
          }
        });
        counter++;
      } else {
        timer?.cancel();
      }
    }

    return CancelableFuture<T>((completer) {
      delayTimer = Timer(delay, () {
        timer = Timer.periodic(interval, (Timer t) => tick(completer));
      });
    }, () {
      delayTimer?.cancel();
      timer?.cancel();
    });
  }
}
