package melody.offline.music

import android.app.Application
import android.content.Context
import android.util.Log
import androidx.annotation.OptIn
import androidx.media3.common.util.UnstableApi
import com.google.android.gms.ads.MobileAds
import com.lol.apex.ok.google.adlibrary.LoLAds
import com.lol.apex.ok.google.adlibrary.bean.constants.TestMode
import melody.offline.music.bean.Audio
import melody.offline.music.bean.CurrentPlayingAudio
import melody.offline.music.bean.ResourcesList
import melody.offline.music.database.AppOfflineDBManager
import melody.offline.music.database.CurrentAudioManager
import melody.offline.music.database.DatabaseManager
import melody.offline.music.media.LocalMediaControllerManager
import melody.offline.music.media.MediaControllerManager
import melody.offline.music.util.CacheManager
import melody.offline.music.util.DownloadUtil
import melody.offline.music.util.parseResources
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import melody.offline.music.database.AppFavoriteDBManager
import melody.offline.music.database.AppPlaylistDBManager
import melody.offline.music.firebase.RemoteConfig
import melody.offline.music.http.CommonIpInfoUtil
import melody.offline.music.http.UploadEventName
import melody.offline.music.sp.AppStore
import melody.offline.music.util.AnalysisUtil
import melody.offline.music.util.AppLifecycleHandler
import java.io.BufferedReader
import java.io.InputStreamReader
import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.atomic.AtomicLong

@OptIn(UnstableApi::class)
class App : Application() {
    companion object {
        lateinit var app: App
            private set
        lateinit var appPlaylistDBManager: AppPlaylistDBManager
            private set
        lateinit var appFavoriteDBManager: AppFavoriteDBManager
            private set
        lateinit var appOfflineDBManager: AppOfflineDBManager
            private set
        lateinit var currentAudioManager: CurrentAudioManager
            private set
        lateinit var databaseManager: DatabaseManager
            private set
        var currentPlayingAudio: CurrentPlayingAudio? = null
            private set
        lateinit var importList: List<Audio>
            private set
        lateinit var resourcesList: ResourcesList
            private set

        lateinit var realHumanVoiceList: List<Audio>
            private set

        lateinit var soundsOfAppliancesList: List<Audio>
            private set

        lateinit var soundsOfNatureList: List<Audio>
            private set

        private var isInitialized = false

        fun initialize(context: Context) {
            if (!isInitialized) {
                val jsonString = readAssetsFile(context)
                resourcesList = parseResources(context, jsonString)
                splitResourcesList()
                isInitialized = true
            }
        }

        fun initCurrentPlayingAudio() {
            CoroutineScope(Dispatchers.IO).launch {
                currentPlayingAudio = currentAudioManager.getCurrentPlayingAudio()
            }
        }

        fun initImportAudio(callback: (List<Audio>) -> Unit = {}) {
            CoroutineScope(Dispatchers.IO).launch {
                importList = databaseManager.getAllAudioFiles()
                withContext(Dispatchers.Main) {
                    callback(importList)
                }
            }
        }

        private fun readAssetsFile(context: Context): String {
            val assetManager = context.assets
            val inputStream = assetManager.open("resources.json")
            val bufferedReader = BufferedReader(InputStreamReader(inputStream))
            val stringBuilder = StringBuilder()
            var line: String?
            while (bufferedReader.readLine().also { line = it } != null) {
                stringBuilder.append(line)
            }
            return stringBuilder.toString()
        }

        private fun splitResourcesList() {
            realHumanVoiceList = mutableListOf()
            soundsOfAppliancesList = mutableListOf()
            soundsOfNatureList = mutableListOf()

            for (category in resourcesList.categories) {
                when (category.name) {
                    "Sound of instrument" -> realHumanVoiceList = category.audios
                    "White noise" -> soundsOfAppliancesList = category.audios
                    "Voice of Nature" -> soundsOfNatureList = category.audios
                }
            }
        }
    }

    var isAdShowing: AtomicBoolean = AtomicBoolean(false)//是否正在广告界面

    var lastAdDisplayTime: AtomicLong = AtomicLong(0L)//上次广告展示的时间

    override fun onCreate() {
        super.onCreate()
        AnalysisUtil.logEvent(AnalysisUtil.USER_LAUNCH)
        app = this
        AppLifecycleHandler(this)
        saveInstallTimeIfNeeded()
        initAd()
        CommonIpInfoUtil.shared.initIPInfo()
        UploadEventName.shared.init(this)
        RemoteConfig.instance.init(this)
        initialize(this)
        MediaControllerManager.init(this)
        LocalMediaControllerManager.init(this)
        appOfflineDBManager = AppOfflineDBManager.getInstance(this)
        appFavoriteDBManager = AppFavoriteDBManager.getInstance(this)
        currentAudioManager = CurrentAudioManager.getInstance(this)
        databaseManager = DatabaseManager.getInstance(this)
        appPlaylistDBManager = AppPlaylistDBManager.getInstance(this)
        initCurrentPlayingAudio()
        initImportAudio()
        CacheManager.initializeCaches(this)
        DownloadUtil.getDownloadManager(this)
    }

    private fun initAd() {
        LoLAds.initialize(this)
        LoLAds.setLogEnable(BuildConfig.DEBUG)//是否打开⽇志和遮罩层颜色，release要设置成false
        LoLAds.setTestEnable(BuildConfig.DEBUG)//false：使用 setAdConfig 中的广告配置
        LoLAds.setTestMode(TestMode.REMOTE_TEST)//setTestEnable为true时生效；LOCAL_TEST: 会使用sdk内的测试广告; REMOTE_TEST: 会将 setAdConfig 添加的配置中的广告id替换成测试id
        LoLAds.setAdConfigKey("Music")//服务器端中⼴告json的key；⻅⼴告配置json详情
        LoLAds.setAdConfig(AppStore(this).adJson)//设置自定义广告配置json
    }

    private fun saveInstallTimeIfNeeded() {//用于弹出评分dialog的条件
        val time = AppStore(this).showRateDialogTime
        if (time == 0L) {//如果time为0L，则表示安装（或者是清除数据）
            val currentTime = System.currentTimeMillis()
            AppStore(this).showRateDialogTime = currentTime
        }
    }
}