package com.gh.gamecenter.core

import android.os.Handler
import android.os.Looper
import com.gh.gamecenter.core.AppExecutor.heavyWeightIoExecutor
import com.gh.gamecenter.core.AppExecutor.ioExecutor
import com.gh.gamecenter.core.AppExecutor.lightWeightIoExecutor
import com.gh.gamecenter.core.AppExecutor.logExecutor
import com.gh.gamecenter.core.AppExecutor.uiExecutor
import com.gh.gamecenter.core.utils.SentryHelper
import com.lightgame.utils.Utils
import io.reactivex.schedulers.Schedulers
import java.util.*
import java.util.concurrent.*

/**
 * APP 线程池管理类
 *
 * [ioExecutor] 是一个最大线程数固定的线程池，较为繁重的 IO 任务可以交给它
 * [uiExecutor] 是主线程的包裹，需要切换至主线程执行可以用它
 * [lightWeightIoExecutor] 是一个单线程的线程池，轻量级且需要保证同一线程的 IO 任务可以交给它
 * [heavyWeightIoExecutor] 是一个重量级任务的线程池，一些高频调用但不用保证结果的任务可以交给它
 * [logExecutor] 是单线程的日志线程池，供上报日志用
 */
object AppExecutor {

    private const val CORE_POOL_SIZE = 3
    private const val MAX_POOL_SIZE = 24

    @JvmStatic
    val uiExecutor by lazy { MainThreadExecutor() }

    @JvmStatic
    val lightWeightIoExecutor: ExecutorService by lazy {
        Executors.newSingleThreadExecutor(
            GHThreadFactory("GH_LIGHT_WEIGHT_IO_THREAD")
        )
    }

    @JvmStatic
    val heavyWeightIoExecutor: ExecutorService by lazy {
        ThreadPoolExecutor(
            0,
            3,
            20L, TimeUnit.SECONDS,
            LinkedBlockingQueue(512),
            GHThreadFactory("GH_HEAVY_WEIGHT_IO_THREAD")
        )
    }

    @JvmStatic
    val logExecutor: ExecutorService by lazy { Executors.newSingleThreadExecutor(GHThreadFactory("GH_LOG_THREAD")) }

    @JvmStatic
    val ioExecutor = ThreadPoolExecutor(
        CORE_POOL_SIZE,
        MAX_POOL_SIZE,
        20L, TimeUnit.SECONDS,
        LinkedBlockingQueue(256),
        GHThreadFactory("GH_IO_THREAD")
    )

    val cachedScheduler by lazy { Schedulers.from(ioExecutor) }

    class MainThreadExecutor : Executor {
        private val mainThreadHandler = Handler(Looper.getMainLooper())

        override fun execute(command: Runnable) {
            mainThreadHandler.post(command)
        }

        fun executeWithDelay(command: Runnable, delay: Long) {
            mainThreadHandler.postDelayed(command, delay)
        }
    }
}

fun runOnIoThread(
    isLightWeightTask: Boolean = false,
    isHeavyWightTask: Boolean = false,
    f: () -> Unit
) {
    when {
        isLightWeightTask -> lightWeightIoExecutor.execute(f)
        isHeavyWightTask -> heavyWeightIoExecutor.execute(f)
        else -> ioExecutor.execute(f)
    }
}

fun runOnUiThread(f: () -> Unit) {
    if (Thread.currentThread() == Looper.getMainLooper().thread) {
        f.invoke()
    } else {
        uiExecutor.execute(f)
    }
}