package com.base.scanqrclear.luma


import android.animation.AnimatorSet
import android.animation.ObjectAnimator
import android.animation.ValueAnimator
import android.annotation.SuppressLint
import android.os.Bundle
import android.view.View
import android.view.animation.LinearInterpolator
import androidx.core.animation.doOnEnd
import androidx.core.view.updatePadding
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import com.base.scanqrclear.R
import com.base.scanqrclear.base.BaseFragment
import com.base.scanqrclear.databinding.FragmentHomeBinding
import com.base.scanqrclear.luma.AdmobHelps.KEY_INSTALL_TIME
import com.base.scanqrclear.luma.AppHelps.dpToPx
import com.base.scanqrclear.utils.ActivityLauncher
import com.base.scanqrclear.utils.BarUtils
import com.gyf.immersionbar.ktx.immersionBar
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.util.concurrent.TimeUnit

class HomeFragment : BaseFragment<FragmentHomeBinding>(FragmentHomeBinding::inflate) {

    private lateinit var launcher: ActivityLauncher

    private val animatorClean by lazy(LazyThreadSafetyMode.NONE) {
        AnimatorSet()
    }

    private var animator1: ValueAnimator? = null

    private var animator2: ValueAnimator? = null

    override fun onResume() {
        super.onResume()
        immersionBar {
            statusBarColor("#ef7246")
            statusBarDarkFont(true)
        }
    }

    override fun onResumeOneShoot() {
        startAnimation()
        initData()
        showDay()
        lifecycle.addObserver(object : DefaultLifecycleObserver {
            override fun onResume(owner: LifecycleOwner) {
                if (animatorClean.isRunning && animatorClean.isPaused) {
                    animatorClean.resume()
                }
                val lottieAnim = binding.lottieAnimation
                if (!lottieAnim.isAnimating) {
                    binding.lottieAnimation.resumeAnimation()
                }

                if (animator1?.isRunning == true && animator1?.isPaused == true) {
                    animator1?.resume()
                }
                if (animator2?.isRunning == true && animator2?.isPaused == true) {
                    animator2?.resume()
                }
            }

            override fun onPause(owner: LifecycleOwner) {
                if (animatorClean.isRunning) {
                    animatorClean.pause()
                }
                val lottieAnim = binding.lottieAnimation
                if (lottieAnim.isAnimating) {
                    binding.lottieAnimation.pauseAnimation()
                }
                if (animator1?.isRunning == true) {
                    animator1?.pause()
                }
                if (animator2?.isRunning == true) {
                    animator2?.pause()
                }
            }
        })
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        launcher = ActivityLauncher(this)
        binding.tvAppName.updatePadding(top = BarUtils.getStatusBarHeight())
        val functionAdapter = FunctionAdapter(getData(), true)
        functionAdapter.callback = object : BaseAdapter.OnClickCallback<FunctionBean> {
            override fun onClicked(view: View, position: Int, item: FunctionBean) {
                ActivityJumpHelps.start(requireContext(), launcher, item.name)
            }
        }
        binding.rvFunction.adapter = functionAdapter
        binding.rvFunction.layoutManager =
            GridLayoutManager(requireContext(), 3, GridLayoutManager.VERTICAL, false)

        val functionMoreAdapter = FunctionMoreAdapter(getMoreData())
        functionMoreAdapter.callback = object : BaseAdapter.OnClickCallback<FunctionBean> {
            override fun onClicked(view: View, position: Int, item: FunctionBean) {
                ActivityJumpHelps.start(requireContext(), launcher, item.name)
            }
        }
        binding.rvMore.adapter = functionMoreAdapter
        binding.rvMore.layoutManager = LinearLayoutManager(requireContext())
        binding.ivShan.setOnClickListener {
            ActivityJumpHelps.start(requireContext(), launcher, R.string.junk_scan)
        }
        binding.tvClean.setOnClickListener {
            ActivityJumpHelps.start(requireContext(), launcher, R.string.junk_scan)
        }
        binding.ivUpward.setOnClickListener {
            val targetY = binding.svNested.getChildAt(0).measuredHeight
            binding.svNested.smoothScrollTo(0, targetY)
        }
    }

    private fun initData() {
        lifecycleScope.launch(Dispatchers.IO) {
            val totalStorage = async { AppHelps.getTotalExternalSize() }
            val availableStorage = async { AppHelps.getAvailableExternalSize() }
            val totalStorageSize = totalStorage.await()
            val availableStorageSize = availableStorage.await()
            val usedMemoryStorageSize = totalStorageSize - availableStorageSize
            val usedMemoryStorageScale = usedMemoryStorageSize * 100 / totalStorageSize

            val totalMemoryUsed = async { AppHelps.getMemTotal(requireContext()) }
            val availableMemoryUsed = async { AppHelps.getMemAvailable(requireContext()) }
            val totalMemoryUsedSize = totalMemoryUsed.await()
            val availableMemoryUsedSize = availableMemoryUsed.await()
            val usedMemoryUsedSize = totalMemoryUsedSize - availableMemoryUsedSize
            val usedMemoryUsedScale: Long = usedMemoryUsedSize * 100 / totalMemoryUsedSize
            withContext(Dispatchers.Main) {
                binding.tvStorageUsed.text = "${usedMemoryStorageScale.toInt()}%"
                binding.tvMemoryUsed.text = "${usedMemoryUsedScale.toInt()}%"
                binding.llStorageUsed.visibility = View.VISIBLE
                binding.llMemoryUsed.visibility = View.VISIBLE
                AnimationHelps.progress(binding.pbStorageUsed, usedMemoryStorageScale.toInt())
                AnimationHelps.progress(binding.pbMemoryUsed, usedMemoryUsedScale.toInt())
            }
        }
    }

    private fun showDay() {
        val installTime = SpUtils.getInstance().getLong(KEY_INSTALL_TIME)
        val result = calculateDaysBetween(installTime, System.currentTimeMillis())
        val day = result.toInt()
        val dayString = if (day > 1) getString(R.string.days) else getString(R.string.day)
        binding.tvDay.text = "$day $dayString"
    }

    fun calculateDaysBetween(timestamp1: Long, timestamp2: Long): Long {
        val diffInMillis = Math.abs(timestamp2 - timestamp1)
        val diffInDays = TimeUnit.MILLISECONDS.toDays(diffInMillis)
        return if (diffInDays < 1) 1 else diffInDays
    }

    private fun getData(): List<FunctionBean> {
        return mutableListOf<FunctionBean>().apply {
            add(FunctionBean(R.mipmap.icon_app_t, R.string.app_process))
            add(FunctionBean(R.mipmap.icon_junk_scan, R.string.junk_scan))
            add(FunctionBean(R.mipmap.icon_similar, R.string.similar_photos))
            add(
                FunctionBean(
                    R.mipmap.icon_whatsapp_clean_t,
                    R.string.whatsapp_clean
                )
            )

        }
    }

    private fun getMoreData(): List<FunctionBean> {
        return mutableListOf<FunctionBean>().apply {
            add(
                FunctionBean(
                    R.mipmap.icon_screenshots_1,
                    R.string.screenshot_clean
                )
            )
        }
    }

    private fun startAnimation() {
        binding.ivCircleBorder.visibility = View.GONE
        val delay: Long = 1200
        animator1?.cancel()
        animator2?.cancel()
        animator1 = ValueAnimator.ofFloat(0f, 360f).apply {
            duration = delay
            interpolator = LinearInterpolator()
            addUpdateListener { animation ->
                val animatedValue = animation.animatedValue as Float
                runCatching {
                    binding.ivShan.rotation = animatedValue * 2
                }
            }
            doOnEnd {
                runCatching {
                    binding.ivCircleBorder.visibility = View.VISIBLE
                    AnimationHelps.rotation(binding.ivShan, 2000)
                }
                animator1 = null
            }
            start()
        }
        binding.tvJunkFiles.alpha = 0f
        animator2 = ValueAnimator.ofFloat(0f, 1f).apply {
            this.duration = 1000
            this.startDelay = delay
            addUpdateListener { animation ->
                val value = animation.animatedValue as Float
                runCatching {
                    binding.tvJunkFiles.alpha = value
                    binding.tvJunkFiles.translationY = (binding.tvClean.height * (1 - value))
                }
            }
            doOnEnd {
                animator2 = null
            }
            start()
        }

        val scaleXAnim =
            ObjectAnimator.ofFloat(binding.ivCircleBorder, "scaleX", 0.85f, 1.35f).apply {
                duration = 2000
                startDelay = delay
                repeatCount = ValueAnimator.INFINITE
                repeatMode = ValueAnimator.RESTART
            }
        val scaleYAnim =
            ObjectAnimator.ofFloat(binding.ivCircleBorder, "scaleY", 0.85f, 1.35f).apply {
                duration = 2000
                startDelay = delay
                repeatCount = ValueAnimator.INFINITE
                repeatMode = ValueAnimator.RESTART
            }
        val alphaAnim = ObjectAnimator.ofFloat(binding.ivCircleBorder, "alpha", 0f, 1f).apply {
            duration = 2000
            startDelay = delay
            repeatCount = ValueAnimator.INFINITE
            repeatMode = ValueAnimator.RESTART
        }

        val widthAnim = ObjectAnimator.ofInt(1, 4).apply {
            duration = 2000
            startDelay = delay
            repeatCount = ValueAnimator.INFINITE
            repeatMode = ValueAnimator.RESTART
            addUpdateListener { animation ->
                val animatedValue = animation.animatedValue as Int
                binding.ivCircleBorder.setStrokeWidth(animatedValue)
            }
        }

        animatorClean.playTogether(scaleXAnim, scaleYAnim, alphaAnim, widthAnim)
        animatorClean.start()

        val top = requireContext().dpToPx(5)
        ObjectAnimator.ofFloat(binding.ivUpward, "translationY", 0f, top).apply {
            duration = 1000
            repeatCount = ValueAnimator.INFINITE
            repeatMode = ValueAnimator.REVERSE
            start()
        }
    }
}