package com.adealink.weparty.network

import android.app.Application
import com.adealink.frame.base.Rlt
import com.adealink.frame.coroutine.dispatcher.Dispatcher
import com.adealink.frame.log.Log
import com.adealink.frame.network.util.removeNetworkCallbacks
import com.adealink.frame.network.util.runNetworkThread
import com.adealink.frame.util.ActivityLifecycleCallbacksExt
import com.adealink.frame.util.AppUtil
import com.adealink.frame.util.OnNetworkListener
import com.adealink.frame.util.registerNetworkListener
import com.adealink.frame.util.unregisterNetworkListener
import com.adealink.weparty.App
import com.adealink.weparty.module.account.AccountModule
import com.adealink.weparty.module.account.ILoginListener
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.launch

/**
 * 网络管理器
 */
class NetworkManager : INetworkManager,
    ILoginListener,
    OnNetworkListener,
    ActivityLifecycleCallbacksExt,
    CoroutineScope by CoroutineScope(SupervisorJob() + Dispatcher.WENEXT_THREAD_POOL) {

    companion object {
        private const val TAG_NETWORK = "tag_network"
        private const val TAG_PING = "tag_ping"
        private const val PING_DEFAULT_INTERVAL = 5 * 1000L
    }

    private val pingHttpService by lazy {
        App.instance.networkService.getHttpService(PingHttpService::class.java)
    }

    private var pingInterval = PING_DEFAULT_INTERVAL
    private val pingRunnable by lazy {
        Runnable {
            ping()
            startPing(pingInterval)
        }
    }

    override fun init(application: Application) {
        AccountModule.registerListener(this)
        if (AccountModule.isLogin()) {
            handleLogin()
        }
    }

    private fun handleLogin() {
        Log.d(TAG_NETWORK, "handleLogin")
        AppUtil.registerActivityLifecycleCallbacks(this)
        registerNetworkListener(this)
        startPing()
    }

    override fun onLogin() {
        super.onLogin()
        handleLogin()
    }

    override fun onLogout() {
        super.onLogout()
        Log.d(TAG_NETWORK, "onLogout")
        AppUtil.unregisterActivityLifecycleCallbacks(this)
        unregisterNetworkListener(this)
        stopPing()
    }

    private fun ping() {
        launch {
            Log.d(TAG_PING, "ping")
            when (val result = pingHttpService.ping()
                .apply { Log.logRltD(TAG_PING, "ping result", this) }
            ) {
                is Rlt.Success -> {

                }

                is Rlt.Failed -> {

                }
            }
        }
    }

    private fun startPing(interval: Long = pingInterval) {
        Log.d(TAG_PING, "startPing, pingInterval:$interval")
        removeNetworkCallbacks(pingRunnable)
        runNetworkThread(pingRunnable, interval)
    }

    private fun stopPing() {
        Log.d(TAG_PING, "stopPing")
        removeNetworkCallbacks(pingRunnable)
    }

    override fun onEnterForeGround() {
        super.onEnterForeGround()
        Log.d(TAG_NETWORK, "onEnterForeGround")
        startPing()
    }

    override fun onEnterBackGround() {
        super.onEnterBackGround()
        Log.d(TAG_NETWORK, "onEnterBackGround")
        stopPing()
    }

    override fun pingNow() {
        Log.d(TAG_PING, "pingNow")
        startPing(interval = 0)
    }

    override fun onNetChanged(available: Boolean) {
        Log.d(TAG_NETWORK, "onNetChanged, available:$available")
        if (available) {
            startPing(0)
        } else {
            stopPing()
        }
    }

}