package com.quyunshuo.module.home.utils


import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.schedulers.Schedulers
import java.util.concurrent.TimeUnit

class PeriodicTask private constructor(builder: Builder) {
    // 配置参数
    private val initialDelay: Long = builder.initialDelay
    private val interval: Long = builder.interval
    private val timeUnit: TimeUnit = builder.timeUnit
    private val retryCount: Int = builder.retryCount

    // 订阅管理
    private val compositeDisposable = CompositeDisposable()

    // 回调接口
    interface Callback {
        fun onNext(attemptCount: Int)
        fun onError(throwable: Throwable)
    }

    fun start(callback: Callback) {
        compositeDisposable.add(
            Observable.interval(initialDelay, interval, timeUnit)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .doOnNext { callback.onNext(it.toInt() + 1) }
                .retryWhen { errors ->
                    errors.zipWith(Observable.range(1, retryCount + 1)) { error, retryCount ->
                        if (retryCount > retryCount) throw error
                        return@zipWith retryCount
                    }.flatMap { retryCount ->
                        Observable.timer(
                            interval * retryCount,
                            timeUnit
                        )
                    }
                }
                .subscribe({}, { callback.onError(it) })
        )
    }

    fun stop() {
        compositeDisposable.clear()
    }

    class Builder {
        var initialDelay: Long = 0
            private set
        var interval: Long = 1
            private set
        var timeUnit: TimeUnit = TimeUnit.SECONDS
            private set
        var retryCount: Int = 3
            private set

        fun initialDelay(delay: Long, unit: TimeUnit) = apply {
            this.initialDelay = delay
            this.timeUnit = unit
        }

        fun interval(interval: Long, unit: TimeUnit) = apply {
            this.interval = interval
            this.timeUnit = unit
        }

        fun retryCount(count: Int) = apply {
            this.retryCount = count
        }

        fun build() = PeriodicTask(this)
    }
}