package com.adealink.weparty.apm

import android.app.Application
import com.adealink.frame.apm.core.APM
import com.adealink.frame.apm.core.base.AbstractPlugin
import com.adealink.frame.apm.core.base.MonitorEvent
import com.adealink.frame.apm.core.stat.AbstractPluginEventHandler
import com.adealink.frame.apm.plugins.largebitmap.LargeBitmapConfig
import com.adealink.frame.apm.plugins.largebitmap.LargeBitmapPlugin
import com.adealink.frame.apm.plugins.largebitmap.LargeBitmapStat
import com.adealink.frame.apm.plugins.memory.memoryleak.LeakStat
import com.adealink.frame.apm.plugins.memory.memoryleak.MemoryConfig
import com.adealink.frame.apm.plugins.memory.memoryleak.MemoryLeakPlugin
import com.adealink.frame.apm.plugins.uiblock.ANRStat
import com.adealink.frame.apm.plugins.uiblock.BlockStat
import com.adealink.frame.apm.plugins.uiblock.UIBlockMonitor
import com.adealink.frame.base.AppBase
import com.adealink.frame.coroutine.dispatcher.Dispatcher
import com.adealink.frame.data.json.toJsonErrorNull
import com.adealink.frame.log.Log
import com.adealink.frame.log.Log.splitLog
import com.adealink.frame.log.data.APMLogType
import com.adealink.frame.log.data.ReportLogReason
import com.adealink.frame.util.AppUtil
import com.adealink.frame.util.ProcessUtil
import com.adealink.weparty.App
import com.adealink.weparty.BuildConfig
import com.adealink.weparty.apm.stat.APMStatEvent
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch

const val TAG_APM = "tag_apm"

fun initAPM(application: Application) {
    if (!ProcessUtil.isUIProcess()) {
        return
    }

    Log.i(TAG_APM, "initAPM")
//    XCrash.init(application) 已在CrashInit中初始化
    APM.init(application) {
        addEventHandler(object : AbstractPluginEventHandler() {
            override fun onEvent(plugin: AbstractPlugin, event: MonitorEvent) {
                stat(plugin, event)
            }
        })

        use(UIBlockMonitor {
            releaseUploadThreshold = 3000
            uiBlockEnable = BuildConfig.DEBUG || !AppBase.isRelease //开发阶段默认开启，线上发布需要灰度收集
        })
        use(LargeBitmapPlugin(
            LargeBitmapConfig.Builder()
                .apply {
                    largeBitmapEnable = BuildConfig.DEBUG || !AppBase.isRelease //只在开发阶段使用
                }
                .build())
        )
        use(
            MemoryLeakPlugin(
                MemoryConfig()
                    .apply {
                        memoryLeakEnable = BuildConfig.DEBUG || !AppBase.isRelease //只在开发阶段使用
                    })
        )
    }
}

// default not on main Thread
private fun stat(plugin: AbstractPlugin, event: MonitorEvent) {
    when (plugin) {
        is UIBlockMonitor -> {
            when (event) {
                is ANRStat -> {
                    reportANR(event)
                }
                is BlockStat -> {
                    reportUiBlock(event)
                }
                else -> {

                }
            }
        }
        is LargeBitmapPlugin -> {
            when (event) {
                is LargeBitmapStat -> {
                    reportLargeBitmap(event)
                }
            }
        }
        is MemoryLeakPlugin -> {
            when (event) {
                is LeakStat -> {
                    reportMemoryLeak(event)
                }
            }
        }
    }
}

private fun reportANR(anrStat: ANRStat) {
    CoroutineScope(Dispatcher.WENEXT_THREAD_POOL).launch {
        val anrEventMap = anrStat.toMap()
        anrEventMap["boot_offset"] = (anrStat.timestamp - App.instance.appStartTime).toString()
        anrEventMap["cur_activity"] = AppUtil.currentActivityName
        APMStatEvent(APMStatEvent.Action.ANR)
            .apply {
                addEventMap(anrEventMap)
            }
            .send()
        val time = System.currentTimeMillis()
        splitLog("$anrEventMap")
            .forEach { Log.i(TAG_APM, "anr($time) = $it") }
        App.instance.logService.uploadLongString("anr($time)", "${toJsonErrorNull(anrEventMap)}")
        App.instance.logService.uploadLog(ReportLogReason.APM(APMLogType.ANR))
    }
}

private fun reportUiBlock(blockStat: BlockStat) {
    CoroutineScope(Dispatcher.WENEXT_THREAD_POOL).launch {
        val blockEventMap = blockStat.toMap()
        APMStatEvent(APMStatEvent.Action.UI_BLOCK)
            .apply {
                addEventMap(blockEventMap)
            }
            .send()
        val time = System.currentTimeMillis()
        splitLog("$blockEventMap")
            .forEach { Log.i(TAG_APM, "ui block($time) = $it") }
        App.instance.logService.uploadLongString("ui block($time)", "${toJsonErrorNull(blockEventMap)}")
        App.instance.logService.uploadLog(ReportLogReason.APM(APMLogType.UI_BLOCK))
    }
}

private fun reportLargeBitmap(stat: LargeBitmapStat) {
    Log.i(TAG_APM, "large bitmap = $stat")
}

private fun reportMemoryLeak(stat: LeakStat) {
    CoroutineScope(Dispatcher.WENEXT_THREAD_POOL).launch {
        val memoryEventMap = stat.toMap()
        APMStatEvent(APMStatEvent.Action.MEMORY_LEAK)
            .apply {
                addEventMap(memoryEventMap)
            }
            .send()
        val time = System.currentTimeMillis()
        splitLog("$memoryEventMap")
            .forEach { Log.i(TAG_APM, "memory leak($time) = $it") }
        App.instance.logService.uploadLongString("memory leak($time)", "${toJsonErrorNull(memoryEventMap)}")
        App.instance.logService.uploadLog(ReportLogReason.APM(APMLogType.MEMORY_LEAK))
    }
}