package com.rgt.superr.base

import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.ValueAnimator
import android.annotation.SuppressLint
import android.app.Activity
import android.app.Dialog
import android.content.Context
import android.content.Intent
import android.graphics.Color
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.animation.LinearInterpolator
import android.widget.LinearLayout
import android.widget.Toast
import androidx.activity.SystemBarStyle
import androidx.activity.addCallback
import androidx.activity.enableEdgeToEdge
import androidx.activity.result.ActivityResult
import androidx.activity.result.ActivityResultCallback
import androidx.annotation.CallSuper
import androidx.annotation.ColorInt
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.AppCompatTextView
import androidx.core.app.ActivityOptionsCompat
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.lifecycle.lifecycleScope
import androidx.viewbinding.ViewBinding
import com.airbnb.lottie.LottieAnimationView
import com.rgt.superr.SpConstObject.appLanguageCountrySp
import com.rgt.superr.SpConstObject.appLanguageSp
import com.rgt.superr.R
import com.rgt.superr.SpConstObject.cleanedSize
import com.rgt.superr.bean.FeatureBean.Companion.BATTERY_INFO
import com.rgt.superr.bean.FeatureBean.Companion.JUNK_CLEAN
import com.rgt.superr.bean.FeatureBean.Companion.LARGE_FILE_CLEAN
import com.rgt.superr.bean.FeatureBean.Companion.PHOTO_COMPRESSION
import com.rgt.superr.bean.FeatureBean.Companion.SCREENSHOT_CLEAN
import com.rgt.superr.bean.FeatureBean.Companion.SIMILAR_PHOTOS
import com.rgt.superr.bean.FeatureBean.Companion.UNINSTALL_APP
import com.rgt.superr.bean.FileBean
import com.rgt.superr.bean.config.AdConfigBean
import com.rgt.superr.business.ads.AdsMgr
import com.rgt.superr.business.ads.AdsShowCallBack
import com.rgt.superr.business.ads.NativeParentView
import com.rgt.superr.business.helper.EventUtils
import com.rgt.superr.ui.appuninstall.AppUninstallActivity
import com.rgt.superr.ui.batteryinfo.BatteryInfoActivity
import com.rgt.superr.ui.clean.JunkCleanActivity
import com.rgt.superr.ui.dialog.FunctionBackDialog
import com.rgt.superr.ui.largefile.LargeFileCleanActivity
import com.rgt.superr.ui.main.MainActivity
import com.rgt.superr.ui.photocompression.PhotoCompressionActivity
import com.rgt.superr.ui.screenshot.ScreenshotCleanActivity
import com.rgt.superr.ui.similar.SimilarPhotosActivity
import com.rgt.superr.utils.ActivityLauncher
import com.rgt.superr.utils.ActivityManagerUtils
import com.rgt.superr.utils.FileUtils
import com.rgt.superr.utils.LogEx
import com.rgt.superr.utils.MediaUtils
import com.rgt.superr.utils.VpnStatusListener
import com.rgt.superr.utils.VpnStatusListener.Companion.vpnFlow
import com.hjq.language.MultiLanguages
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import java.io.File
import java.util.Locale
import java.util.concurrent.atomic.AtomicBoolean
import kotlin.apply
import kotlin.jvm.java
import kotlin.jvm.javaClass
import kotlin.random.Random
import kotlin.text.contains

abstract class BaseActivity<VB : ViewBinding>(
    bindingInflater: (LayoutInflater) -> VB
) : AppCompatActivity() {

    open val TAG = javaClass.simpleName
    private val tagNo = Random.nextInt(500)
    val binding by lazy(LazyThreadSafetyMode.NONE) {
        bindingInflater(layoutInflater)
    }

    lateinit var launcher: ActivityLauncher
    private var currentLocale: Locale? = null
    lateinit var vpnStatusListener: VpnStatusListener

    var onCreateI = 0
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setStatusBarColor()
        onCreateI++
        LogEx.logDebug(TAG, "lifecycle $tagNo onCreate ${javaClass.simpleName} $onCreateI")
        launcher = ActivityLauncher(this)
        setContentView(binding.root)
        useDefaultImmersive()
        EventUtils.event("page_${javaClass.simpleName}")
        currentLocale = Locale(appLanguageSp, appLanguageCountrySp)
        initView()
        initListener()
        vpnStatusListener = VpnStatusListener(this)
        lifecycleScope.launch {
            vpnFlow.collectLatest {
                actionVpn(it)
            }
        }
    }

    protected open fun actionVpn(isVpn: Boolean) {
//        if (configBean.vpnCanUse) return
//        if (isVpn) {
//            if (this !is VpnBlockActivity) {
//                val intent = Intent(this, VpnBlockActivity::class.java)
//                startActivity(intent)
//                finish()
//                Log.e("VpnStatusListener", "startActivity")
//            }
//        } else {
//        }
    }

    @CallSuper
    protected open fun initView() {
        setBackPressed()
    }

    protected open fun initListener() {}


    fun finishToMain(delay: Long = 0) {
        val flag = this !is MainActivity && !ActivityManagerUtils.getInstance().isActivityInStack(MainActivity::class.java)
        if (flag) {
            startActivity(Intent(this, MainActivity::class.java).apply {
                putExtra("where", "finishToMain")
            })
        }
        lifecycleScope.launch(Dispatchers.Main) {
            delay(delay)
            finish()
        }
    }

    fun finishToMainTop() {
        val intent = Intent(this, MainActivity::class.java)
        intent.putExtra("where", "finishToMainTop")
//        intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT)
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP)
        startActivity(intent)
    }

    var dialog: Dialog? = null
    override fun onDestroy() {
        super.onDestroy()
        ActivityManagerUtils.getInstance().removeActivity(this)
        if (dialog != null) {
            dialog?.dismiss()
            dialog = null
        }
        vpnStatusListener.stopListen()
    }

    override fun attachBaseContext(newBase: Context?) {
        super.attachBaseContext(MultiLanguages.attach(newBase))
    }

    fun changeLanguage(currentActivity: Activity, bundle: Bundle = Bundle()): Boolean {
        val spLanguage = Locale(appLanguageSp, appLanguageCountrySp)
        val flag = currentLocale != spLanguage
        val restart = MultiLanguages.setAppLanguage(this, spLanguage)
        LogEx.logDebug(
            TAG, "changeLanguage " +
                    "flag=$flag  restart=$restart currentLocale=$currentLocale spLanguage=$spLanguage"
        )
        if (restart) {
            currentLocale = Locale(appLanguageSp, appLanguageCountrySp)
        }

        if (flag || restart) {
            // 1.使用 recreate 来重启 Activity，效果差，有闪屏的缺陷
//             recreate();

            // 2.使用常规 startActivity 来重启 Activity，有从左向右的切换动画
            // 稍微比 recreate 的效果好一点，但是这种并不是最佳的效果
            // startActivity(new Intent(this, LanguageActivity.class));
            // finish();

            // 3.我们可以充分运用 Activity 跳转动画，在跳转的时候设置一个渐变的效果，相比前面的两种带来的体验是最佳的
            //需要设置启动模式，避免AndroidManifest.xml设置singleTop启动模式导致重复启动不生效
            //这种方式如果设置了singleTop或者singleTask的，再次回到该activity无法改变于语言，因为还在堆栈里没有重新创建
            needRecreate()
            if (needRecreate()) {
                LogEx.logDebug(TAG, "changeLanguage recreate")
                recreate()
            } else {
                startActivity(Intent(this, currentActivity::class.java).apply {
                    putExtras(bundle)
                })
                overridePendingTransition(R.anim.activity_alpha_in, R.anim.activity_alpha_out)
                finish()
            }
            return true
        }
        return false
    }

    /**
     * 判断是否需要重新创建对SingleTop启动模式的有效
     */
    fun needRecreate(): Boolean {
        return TAG.contains("MainActivity")
    }

    /**
     * 避免在onResume--onPause周期内,多次调用
     * 在onStop中重置标志
     */
    private val onResumeCalled = AtomicBoolean(false)
    private var onResumeOneShootI = 0
    open fun onResumeOneShoot() {
        onResumeOneShootI++
        LogEx.logDebug(TAG, "lifecycle $tagNo onResumeOneShoot ${javaClass.simpleName} $onResumeOneShootI")
    }

    private var onResumeI = 0
    override fun onResume() {
        super.onResume()
        onResumeI++
        LogEx.logDebug(TAG, "lifecycle $tagNo onResume ${javaClass.simpleName} $onResumeI")
        vpnStatusListener.startListen()

        if (!onResumeCalled.get()) {
            onResumeCalled.set(true)
            onResumeOneShoot()
        }

        actionVpn(vpnFlow.value)
    }

    private var onStartI = 0
    override fun onStart() {
        super.onStart()
        onStartI++
        LogEx.logDebug(TAG, "lifecycle $tagNo onStart ${javaClass.simpleName} $onStartI")
    }

    private var onStopI = 0
    override fun onStop() {
        super.onStop()
        onStopI++
        LogEx.logDebug(TAG, "lifecycle $tagNo onStop ${javaClass.simpleName} $onStopI")
        onResumeCalled.set(false)
    }

    private var onPauseI = 0
    override fun onPause() {
        super.onPause()
        onPauseI++
        LogEx.logDebug(TAG, "lifecycle $tagNo onPause ${javaClass.simpleName} $onPauseI")
    }

    open fun setStatusBarColor(@ColorInt color: Int = Color.TRANSPARENT, isLight: Boolean = true) {
        enableEdgeToEdge(
            if (isLight) SystemBarStyle.light(color, color) else SystemBarStyle.dark(color)
        )
    }

    open fun useDefaultImmersive() {
        ViewCompat.setOnApplyWindowInsetsListener(binding.root) { v, insets ->
            val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
            v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
            insets
        }
    }


    fun goToAc(
        clazz: Class<out Activity>,
        options: ActivityOptionsCompat? = null,
        exb: (Intent.() -> Unit)? = null,
        activityResultCallback: ActivityResultCallback<ActivityResult>? = null
    ) {
        launcher.launch(
            Intent(this, clazz).apply {
                exb?.let { this.it() }
            }, options, activityResultCallback
        )
    }


    @SuppressLint("SetTextI18n")
    open fun showAdAnimation(
        lottieConfig: LottieEnum,
        finish: (() -> Unit)? = null
    ) {

        if (isBackDisable) return

        isBackDisable = true


        var actionFinsh = {
            isBackDisable = false
            finish?.invoke()
        }

        val adNext = {

            val include: View? = findViewById(R.id.layout_animation)
            val flAd: NativeParentView? = findViewById(R.id.include_flAd)
            var tvProgress: AppCompatTextView? = findViewById(R.id.tv_progress)
            val lottie: LottieAnimationView? = findViewById(R.id.lottie_animation)
            val llTrustlook: LinearLayout = findViewById(R.id.llTrustlook)

            include?.let {
                it.visibility = View.VISIBLE
                it.setOnClickListener { }
            }

            flAd?.let { AdsMgr.showNative(it, R.layout.layout_admob_native_custom) }

            lottie?.let {
                lottieConfig.images?.let { img -> it.imageAssetsFolder = img }
                it.setAnimation(lottieConfig.data)
                it.loop(lottieConfig.isLoop)
                it.playAnimation()
            }


            when (lottieConfig) {
                LottieEnum.CLEAN_LOTTIE -> {
                    lottie?.addAnimatorUpdateListener { animation ->
                        val value = animation.animatedValue as Float * 100
                        tvProgress?.text = "${value.toInt()}%"
                        if (value.toInt() == 100) {
                            include?.visibility = View.GONE
                            actionFinsh.invoke()

                        }
                    }
                }

                else -> {

                    if (lottieConfig == LottieEnum.MALWARE_SCAN) {
                        llTrustlook.visibility = View.VISIBLE
                    }

                    lifecycleScope.launch {
                        val durationTime = Random.Default.nextLong(3000, 4000)
                        ValueAnimator.ofInt(0, 100).apply {
                            duration = durationTime
                            interpolator = LinearInterpolator()
                            addUpdateListener { animation ->
                                val value = animation.animatedValue as Int
                                tvProgress?.text = "${value}%"
                            }
                            addListener(object : AnimatorListenerAdapter() {
                                override fun onAnimationEnd(animation: Animator) {
                                    include?.visibility = View.GONE
                                    lottie?.cancelAnimation()
                                    actionFinsh.invoke()
                                }
                            })
                        }.start()
                    }
                }
            }

        }

        functionInAd { adNext.invoke() }

    }


    protected var isBackDisable = false
    private fun setBackPressed() {
        onBackPressedDispatcher.addCallback {
            handleBackCallBack()
        }
    }

    protected open fun handleBackCallBack() {
        if (isBackDisable) {
            Toast.makeText(
                applicationContext,
                getString(R.string.wait_a_moment),
                Toast.LENGTH_SHORT
            ).show()
        } else {
            FunctionBackDialog(this@BaseActivity).showDialog {
                backAdJump()
            }
        }
    }


    private fun backAdJump() {
        if (AdConfigBean.adsConfigBean.functionBackShowAd) {
            AdsMgr.showInsert(this, showCallBack = object : AdsShowCallBack() {
                override fun next() {
                    finishToMainTop()
                }
            })
        } else {
            finishToMainTop()
        }
    }

    fun functionInAd(next: (() -> Unit)? = null) {
        if (AdConfigBean.adsConfigBean.functionInShowAd) {
            AdsMgr.showInsert(this, showCallBack = object : AdsShowCallBack() {
                override fun next() {
                    next?.invoke()
                }
            })
        } else {
            next?.invoke()
        }
    }
}


fun Activity.jumpAction(key: String) {
    if (this !is BaseActivity<*>) {
        throw Exception("")
    }
    when (key) {
        BATTERY_INFO -> {
            goToAc(BatteryInfoActivity::class.java)
        }

        JUNK_CLEAN -> {
            goToAc(JunkCleanActivity::class.java)
        }

        LARGE_FILE_CLEAN -> {
            goToAc(LargeFileCleanActivity::class.java)
        }

        SCREENSHOT_CLEAN -> {
            goToAc(ScreenshotCleanActivity::class.java)
        }

        SIMILAR_PHOTOS -> {
            goToAc(SimilarPhotosActivity::class.java)
        }

        PHOTO_COMPRESSION -> {
            goToAc(PhotoCompressionActivity::class.java)
        }

        UNINSTALL_APP -> {
            goToAc(AppUninstallActivity::class.java)
        }
    }
}


enum class LottieEnum(val data: String, val images: String? = null, val isLoop: Boolean = true) {
    BATTERY_INFO_LOTTIE("battery_info/scan/data.json", "battery_info/scan/images", true),
    CLEAN_LOTTIE("clean.json"),
    LARGE_FILE_LOTTIE("large_files/scan/data.json", "large_files/scan/images"),
    SCREENSHOT_LOTTIE("screenshot/scan/data.json", "screenshot/scan/images"),
    SIMILAR_PHOTOS_LOTTIE("similar_photos/scan/data.json", "similar_photos/scan/images"),
    PHOTO_COMPRESSION_LOTTIE("photo_compression/scan/data.json", "photo_compression/scan/images"),
    MALWARE_SCAN("malware_scan/scan/data.json", "malware_scan/scan/images"),
}


fun AppCompatActivity.cleanFileBeans(list: List<FileBean>) {
    lifecycleScope.launch(Dispatchers.IO) {
        val paths = list.filter { it.isSelected }.map { it.path }.toTypedArray()
        paths.forEach {
            val file = File(it)
            cleanedSize = cleanedSize + file.length()
            FileUtils.deleteFile(it)
        }
        launch(Dispatchers.Main) { MediaUtils.updateMedia(applicationContext, paths) }
    }
}


