package com.adealink.weparty

import android.content.Context
import android.content.SharedPreferences
import android.content.res.Configuration
import android.os.SystemClock
import com.adealink.frame.aab.AAB
import com.adealink.frame.apm.initAPMService
import com.adealink.frame.base.AppBase
import com.adealink.frame.crash.installCrashProtector
import com.adealink.frame.debug.datasource.performanceDataController
import com.adealink.frame.debug.floatkit.floatKitManager
import com.adealink.frame.deviceid.createDeviceIdService
import com.adealink.frame.download.IDownloadService
import com.adealink.frame.download.createDownloadService
import com.adealink.frame.download.initDownloadService
import com.adealink.frame.effect.IEffect
import com.adealink.frame.effect.createEffect
import com.adealink.frame.effect.initEffect
import com.adealink.frame.googleservice.createGoogleService
import com.adealink.frame.image.imageService
import com.adealink.frame.initStorageService
import com.adealink.frame.locale.language.createLanguageManager
import com.adealink.frame.locale.location.ILocationManager
import com.adealink.frame.locale.location.createLocationManager
import com.adealink.frame.log.Log
import com.adealink.frame.log.XLogHelper
import com.adealink.frame.log.manager.ILogService
import com.adealink.frame.log.manager.LogService
import com.adealink.frame.media.createMediaService
import com.adealink.frame.network.INetworkService
import com.adealink.frame.network.NetworkService
import com.adealink.frame.oss.IOssService
import com.adealink.frame.router.Router
import com.adealink.frame.router.manager.deeplinkRouterManager
import com.adealink.frame.security.createSecurityService
import com.adealink.frame.share.initShareManager
import com.adealink.frame.startup.dispatcher.StartTaskDispatcher
import com.adealink.frame.startup.task.MainThreadStartUpTask
import com.adealink.frame.startup.task.StartUpTask
import com.adealink.frame.startup.task.SubNoWaitStartUpTask
import com.adealink.frame.startup.task.SubWaitStartUpTask
import com.adealink.frame.statistics.initStat
import com.adealink.frame.storage.file.logPath
import com.adealink.frame.storageService
import com.adealink.frame.util.ActivityLifecycleCallbacksExt
import com.adealink.frame.util.AppUtil
import com.adealink.frame.util.ScreenAutoSizeUtil
import com.adealink.frame.util.registerNetworkReceiver
import com.adealink.weparty.aab.AABConfig
import com.adealink.weparty.apm.APMConfig
import com.adealink.weparty.apm.initAPM
import com.adealink.weparty.base.AppBaseImpl
import com.adealink.weparty.commonui.WEUI
import com.adealink.weparty.commonui.widget.floatview.WindowManagerProxy
import com.adealink.weparty.constant.TAG_TIME_APP_START
import com.adealink.weparty.constant.TAG_TOO_LARGE_TOOL
import com.adealink.weparty.constant.logTime
import com.adealink.weparty.crash.CrashConfig
import com.adealink.weparty.crash.initCrash
import com.adealink.weparty.debug.Debug
import com.adealink.weparty.debug.DebugPrefs
import com.adealink.weparty.deeplink.DeepLinkConfig
import com.adealink.weparty.deviceidservice.DeviceIdServiceConfig
import com.adealink.weparty.download.DownloadConfig
import com.adealink.weparty.effect.EffectConfig
import com.adealink.weparty.effect.SVGA_CONFIG
import com.adealink.weparty.googleservice.GoogleServiceConfig
import com.adealink.weparty.hardware.HardwareManager
import com.adealink.weparty.hardware.IHardwareManager
import com.adealink.weparty.image.ImageConfig
import com.adealink.weparty.locale.LanguageConfig
import com.adealink.weparty.location.LocationConfig
import com.adealink.weparty.log.LogConfig
import com.adealink.weparty.media.IMediaManager
import com.adealink.weparty.media.MediaConfig
import com.adealink.weparty.media.MediaManager
import com.adealink.weparty.module.call.CallModule
import com.adealink.weparty.module.im.IMModule
import com.adealink.weparty.network.INetworkManager
import com.adealink.weparty.network.NetworkConfig
import com.adealink.weparty.network.NetworkManager
import com.adealink.weparty.oss.OssService
import com.adealink.weparty.router.RouterConfig
import com.adealink.weparty.security.SecurityConfig
import com.adealink.weparty.share.ShareConfig
import com.adealink.weparty.stat.StatConfig
import com.adealink.weparty.storage.config.StorageConfig
import com.adealink.weparty.webview.JSBridgeConfig
import com.adealink.weparty.webview.WebResourceConfig
import com.adealink.weparty.webview.jsbridge.manager.createJSBridgeManager
import com.adealink.weparty.webview.jsbridge.manager.initJSBridgeManager
import com.adealink.weparty.webview.loader.initWebResourceLoader
import com.adjust.sdk.Adjust
import com.adjust.sdk.AdjustConfig
import com.adjust.sdk.LogLevel
import com.facebook.FacebookSdk
import com.facebook.LoggingBehavior
import com.google.android.play.core.splitcompat.SplitCompatApplication
import com.google.firebase.analytics.FirebaseAnalytics
import com.google.firebase.analytics.FirebaseAnalytics.UserProperty.ALLOW_AD_PERSONALIZATION_SIGNALS
import com.gu.toolargetool.DefaultFormatter
import com.gu.toolargetool.Logger
import com.gu.toolargetool.TooLargeTool
import com.opensource.svgaplayer.control.SVGAManager
import com.tencent.mars.xlog.Xlog

/**
 * WARN: 启动路径代码使用Lambda，aab机制会导致部分机型启动崩溃
 */
class App : SplitCompatApplication(), ActivityLifecycleCallbacksExt {

    companion object {
        lateinit var instance: App
    }

    val networkService: INetworkService by lazy { NetworkService.create(NetworkConfig()) }
    private val networkManager: INetworkManager by lazy { NetworkManager() }
    val ossService: IOssService by lazy { OssService }
    val downloadService: IDownloadService by lazy { createDownloadService(DownloadConfig()) }
    val effect: IEffect by lazy { createEffect(EffectConfig()) }
    val googleService by lazy { createGoogleService(GoogleServiceConfig()) }
    val deviceIdService by lazy { createDeviceIdService(DeviceIdServiceConfig()) }

    val jsBridgeManager by lazy { createJSBridgeManager(JSBridgeConfig()) }
    val mediaService by lazy { createMediaService(MediaConfig) }
    val mediaManager: IMediaManager by lazy { MediaManager() }
    val languageManager by lazy { createLanguageManager(LanguageConfig()) }
    val securityService by lazy { createSecurityService(SecurityConfig()) }

    //    val database by lazy {
//        Room.databaseBuilder(applicationContext, AppDatabase::class.java, "weparty_app_db").build()
//    }
    val logService: ILogService by lazy { LogService(LogConfig()) }
    val hardwareManager: IHardwareManager by lazy { HardwareManager() }

    val locationManager: ILocationManager by lazy { createLocationManager(LocationConfig()) }

    var appStartTime = 0L
    override fun attachBaseContext(base: Context?) {
        logTime(TAG_TIME_APP_START, "app attachBaseContext start")
        instance = this
        AppBase.init(AppBaseImpl())
        AppUtil.init(this)
        super.attachBaseContext(base)
        appStartTime = SystemClock.elapsedRealtime()
        AppUtil.registerActivityLifecycleCallbacks(this)
        logTime(TAG_TIME_APP_START, "app attachBaseContext end")
    }

    override fun onCreate() {
        super.onCreate()
        val appOnCreateTs = SystemClock.elapsedRealtime()
        Log.i(TAG_TIME_APP_START, "app onCreate start")
        //基础任务
        baseStartTask()
        //APP并发初始化任务
        StartTaskDispatcher.create().apply {
            addAppStartTask(InitNetwork())
            addAppStartTask(InitPush())
            addAppStartTask(InitUI())
            addAppStartTask(InitSVGA())
            addAppStartTask(InitImageService())
            addAppStartTask(InitRouter())
            addAppStartTask(InitLanguage())
            addAppStartTask(InitSecurityService())
            addAppStartTask(InitGoogleService())
            addAppStartTask(InitStorageService())
            addAppStartTask(InitShareManager())
            addAppStartTask(InitJSBridgeManager())
            addAppStartTask(InitWebResourceLoader())
            addAppStartTask(InitDownloadService())
            addAppStartTask(InitEffect())
            addAppStartTask(InitFirebaseAnalytics())
            addAppStartTask(InitFB())
            addAppStartTask(InitAdjust())

            addAppStartTask(InitIM())
            addAppStartTask(InitCall())

            //其他子任务(不卡主流程)
            addAppStartTask(InitOther())

            if (!AppBase.isRelease) {
                addAppStartTask(InitDebugKit())
            }

        }.start().await()
        Log.i(
            TAG_TIME_APP_START,
            "app onCreate end, cost:${SystemClock.elapsedRealtime() - appOnCreateTs}"
        )
    }

    /**
     * 所有模块最基础启动任务,必须执行完该任务才能执行其他启动任务
     * - 日志
     * - 组件/模块配置
     */
    private fun baseStartTask() {
        val startTs = SystemClock.elapsedRealtime()
        Log.i(TAG_TIME_APP_START, "baseStartTask start")
        initXLog()
        initAPMService(APMConfig())
        initAPM(this@App)
        initStat { StatConfig() }
        installCrashProtector(CrashConfig())
        initCrash(this@App) //依赖xlog,stat,crash protector
        AAB.init(AABConfig())
        Log.i(
            TAG_TIME_APP_START,
            "baseStartTask end, cost: ${SystemClock.elapsedRealtime() - startTs}"
        )
    }

    private fun initXLog() {
        XLogHelper.initXLog(
            if (BuildConfig.OFFICIAL || BuildConfig.DEBUG) Xlog.LEVEL_ALL else Xlog.LEVEL_INFO,
            logPath,
            logPath,
            BuildConfig.DEBUG
        )
        Log.setLogConfig(LogConfig())
    }

    /**
     * APP初始化任务(阻塞主线程)
     */
    inner class InitPush : MainThreadStartUpTask() {
        override fun run() {
//            pushService.init(PushServiceConfig())
//            NotificationUtil.createNotificationChannel(getCompatString(R.string.channel_event))
        }
    }

    inner class InitUI : MainThreadStartUpTask() {
        override fun run() {
            //UI初始化
            WEUI.init(this@App)
            ScreenAutoSizeUtil.init(this@App, !AppBase.isRelease)
            WindowManagerProxy.init()
        }
    }

    inner class InitImageService : MainThreadStartUpTask() {
        override fun run() {
            imageService.init(ImageConfig())
        }

        override val dependsTaskList: List<Class<out StartUpTask>>
            get() = listOf(InitUI::class.java)
    }

    inner class InitSVGA : SubWaitStartUpTask() {
        override fun run() {
            SVGAManager.init(this@App, SVGA_CONFIG)
        }

        override val dependsTaskList: List<Class<out StartUpTask>>
            get() = listOf(InitUI::class.java)
    }

    inner class InitRouter : SubWaitStartUpTask() {
        override fun run() {
            Router.config = RouterConfig()
            deeplinkRouterManager.init(DeepLinkConfig())
        }
    }

    inner class InitLanguage : SubWaitStartUpTask() {
        override fun run() {
            languageManager.init()
        }
    }

    inner class InitSecurityService : SubWaitStartUpTask() {
        override fun run() {
            securityService.init()
        }
    }

    inner class InitGoogleService : SubWaitStartUpTask() {
        override fun run() {
            googleService.init()
        }
    }

    inner class InitStorageService : SubWaitStartUpTask() {
        override fun run() {
            initStorageService(StorageConfig())
        }
    }

    inner class InitShareManager : SubWaitStartUpTask() {
        override fun run() {
            initShareManager(ShareConfig())
        }
    }

//    inner class InitOssService : SubWaitStartUpTask() {
//        override fun run() {
////            initOssService { ossService }
//        }
//    }

    inner class InitJSBridgeManager : SubWaitStartUpTask() {
        override fun run() {
            initJSBridgeManager { jsBridgeManager }
        }
    }

    inner class InitWebResourceLoader : SubWaitStartUpTask() {
        override fun run() {
            initWebResourceLoader(WebResourceConfig())
        }

        override val dependsTaskList: List<Class<out StartUpTask>>
            get() = listOf(InitNetwork::class.java)
    }

    inner class InitDownloadService : SubWaitStartUpTask() {
        override fun run() {
            initDownloadService { downloadService }
        }

        override val dependsTaskList: List<Class<out StartUpTask>>
            get() = listOf(InitNetwork::class.java)
    }

    inner class InitEffect : SubWaitStartUpTask() {
        override fun run() {
            initEffect { effect }
        }
    }

    inner class InitFirebaseAnalytics : SubWaitStartUpTask() {
        override fun run() {
            val analytics = FirebaseAnalytics.getInstance(applicationContext)
            analytics.setUserProperty(ALLOW_AD_PERSONALIZATION_SIGNALS, "true")
            analytics.setAnalyticsCollectionEnabled(true)
        }
    }

    inner class InitFB : SubWaitStartUpTask() {
        override fun run() {
            if (!AppBase.isRelease) {
                FacebookSdk.setIsDebugEnabled(AppBase.isRelease)
                FacebookSdk.addLoggingBehavior(LoggingBehavior.APP_EVENTS)
            }
        }
    }

    inner class InitAdjust : SubWaitStartUpTask() {
        override fun run() {
            val config = if (AppBase.isRelease) {
                AdjustConfig(
                    this@App,
                    BuildConfig.ADJUST_TOKEN,
                    AdjustConfig.ENVIRONMENT_PRODUCTION
                ).apply {
                    setLogLevel(LogLevel.INFO)
                }
            } else {
                AdjustConfig(
                    this@App,
                    BuildConfig.ADJUST_TOKEN,
                    AdjustConfig.ENVIRONMENT_SANDBOX
                ).apply {
                    setLogLevel(LogLevel.VERBOSE)
                }
            }
            config.setOnDeferredDeeplinkResponseListener { deeplink ->

                true
            }
            config.externalDeviceId
            Adjust.initSdk(config)
        }
    }

    inner class InitNetwork : SubWaitStartUpTask() {
        override fun run() {
            networkManager.init(this@App)
            registerNetworkReceiver()
        }
    }

    inner class InitIM : SubWaitStartUpTask() {
        override fun run() {
            IMModule.appOnCreateMainTask(this@App)
        }
    }

    inner class InitCall : SubWaitStartUpTask() {
        override val isRunOnMainThread: Boolean = true
        override fun run() {
            CallModule.appOnCreateMainTask(this@App)
        }
    }

    inner class InitDebugKit : SubWaitStartUpTask() {
        override val isRunOnMainThread: Boolean = true

        override fun run() {
            if (AppBase.isRelease) {
                return
            }
            if (DebugPrefs.showPerformanceFloatView) {
                floatKitManager.install(this@App, true)
                floatKitManager.onMainIconDoubleClick = {
                    AppUtil.currentActivity?.let {
                        Router.build(it, Debug.Debug.PATH).start()
                    }
                }
                performanceDataController.start()
            }
            TooLargeTool.startLogging(this@App, DefaultFormatter(), object : Logger {
                override fun log(msg: String) {
                    Log.i(TAG_TOO_LARGE_TOOL, msg)
                }

                override fun logException(e: Exception) {
                    Log.e(TAG_TOO_LARGE_TOOL, "logException", e)
                }
            })
        }
    }

    /**
     * 其他任务(非阻塞主线程)
     */
    inner class InitOther : SubNoWaitStartUpTask() {
        override fun run() {
            deviceIdService.updateDeviceId()
            networkService.fetchNetAntiBanConfig()

//            AttributionModule.initialize()
//            AttributionModule.start()
//            AttributionModule.reportFirstOpen()
//
//            OperationModule.init()
        }
    }

    override fun onTerminate() {
        super.onTerminate()
        Log.appenderClose()
    }

    override fun onConfigurationChanged(newConfig: Configuration) {
        super.onConfigurationChanged(newConfig)
        languageManager.onConfigurationChanged(newConfig)
    }

    override fun getSharedPreferences(name: String, mode: Int): SharedPreferences {
        if (name == "") {
            return super.getSharedPreferences(name, mode)
        }
        return storageService.hookSharedPreferences(
            name,
            mode,
            super.getSharedPreferences(name, mode)
        )
    }

    override fun onTrimMemory(level: Int) {
        super.onTrimMemory(level)
        imageService.onTrimMemory(level)
    }

    /**
     * 立即ping网络状态
     */
    fun pingNow() {
        networkManager.pingNow()
    }

}