package com.gh.common.dialog

import android.animation.ValueAnimator
import android.content.Context
import android.content.pm.PackageInfo
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.animation.LinearInterpolator
import android.widget.LinearLayout
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.fragment.app.FragmentTransaction
import androidx.lifecycle.Lifecycle
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.gh.common.util.DirectUtils
import com.gh.common.util.LogUtils
import com.gh.common.util.PackageUtils
import com.gh.download.DownloadManager
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.BaseRecyclerViewHolder
import com.gh.gamecenter.common.callback.ConfirmListener
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.entity.LinkEntity
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.common.view.CustomLinkMovementMethod
import com.gh.gamecenter.core.utils.DisplayUtils
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.core.utils.SpanBuilder
import com.gh.gamecenter.databinding.FragmentPackageCheckBinding
import com.gh.gamecenter.databinding.PackageCheckItemBinding
import com.gh.gamecenter.entity.DetectionObjectEntity
import com.gh.gamecenter.entity.GameEntity
import com.gh.gamecenter.entity.PackageDialogEntity
import com.gh.gamecenter.eventbus.EBPackage
import com.halo.assistant.HaloApp
import com.lightgame.adapter.BaseRecyclerAdapter
import com.lightgame.dialog.BaseDialogFragment
import com.lightgame.download.DataWatcher
import com.lightgame.download.DownloadEntity
import com.lightgame.download.DownloadStatus
import io.reactivex.disposables.Disposable
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode

/**
 * 包名检测弹窗
 */
// TODO 将 gameEntity 放到 argument 里再取出，避免重建时为空
class PackageCheckDialogFragment : BaseDialogFragment() {

    private lateinit var binding: FragmentPackageCheckBinding
    private var mTotalWidth = 0f
    private val mDuration = 3000
    private var mDisposable: Disposable? = null
    private var mAdapter: PackageCheckAdapter? = null
    private var mAllInstalledPackages = PackageUtils.getInstalledPackages(HaloApp.getInstance().application, 0)
    var gameEntity: GameEntity? = null
    var callBack: ConfirmListener? = null

    private val dataWatcher = object : DataWatcher() {
        override fun onDataChanged(downloadEntity: DownloadEntity) {
            val packageName = downloadEntity.packageName
            val detectionObjects = gameEntity?.packageDialog?.detectionObjects
            if (DownloadStatus.add == downloadEntity.status || DownloadStatus.done == downloadEntity.status) {
                detectionObjects?.forEach { detectionObject ->
                    if (detectionObject.packages.contains(packageName)) {
                        val packageLink = gameEntity?.packageDialog?.links?.find { it.buttonLink }
                        LogUtils.uploadPackageCheck(
                            "pkg_check_pop_download",
                            if (DownloadStatus.add == downloadEntity.status) "下载开始" else "下载完成",
                            gameEntity,
                            packageLink?.text ?: "",
                            packageLink?.title
                                ?: "",
                            downloadEntity.gameId,
                            downloadEntity.getMetaExtra(Constants.GAME_NAME)
                        )
                    }
                }
            }
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        EventBus.getDefault().register(this)
        gameEntity?.let {
            LogUtils.uploadPackageCheck("pkg_check_pop_click", "出现弹窗", it, "", "", "", "")
        }
    }

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        binding = FragmentPackageCheckBinding.inflate(inflater, container, false)
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        gameEntity?.packageDialog?.let {
            changeParams(it.detectionObjects.size)

            binding.packageRv.layoutManager = LinearLayoutManager(requireContext())
            mAdapter = PackageCheckAdapter(requireContext(), it.detectionObjects)
            binding.packageRv.adapter = mAdapter

            binding.titleTv.text = it.title
            binding.contentTv.text = it.content

            val spanBuilder = SpanBuilder(it.linkHintText).build()
            it.links.forEachIndexed { index, link ->
                val linkSpan = SpanBuilder(link.title ?: "").click(
                    requireContext(),
                    0,
                    (link.title ?: "").length,
                    R.color.theme_font,
                    true
                ) {
                    LogUtils.uploadPackageCheck(
                        "pkg_check_pop_click",
                        "点击链接",
                        gameEntity,
                        link.text,
                        link.title,
                        "",
                        ""
                    )
                    DirectUtils.directToLinkPage(requireContext(), link, "包名检测弹窗", "")
                }.build()
                spanBuilder.append(linkSpan)
                if (index != it.links.size - 1) {
                    spanBuilder.append("、")
                }
            }
            binding.linkHintTv.text = spanBuilder
            binding.linkHintTv.movementMethod = CustomLinkMovementMethod.getInstance()

            when (it.level) {
                "HINT_SKIP" -> {
                    binding.cancelTv.text = "取消"
                    binding.noRemindAgainCb.visibility = View.GONE
                }
                "ALWAYS_HINT" -> {
                    binding.cancelTv.text = "我知道了"
                    binding.noRemindAgainCb.visibility = View.GONE
                }
                "OPTIONAL_CURRENT_HINT" -> {
                    binding.cancelTv.text = "我知道了"
                    binding.noRemindAgainCb.visibility = View.VISIBLE
                }
                else -> {
                    binding.cancelTv.text = "我知道了"
                    binding.noRemindAgainCb.visibility = View.VISIBLE
                }
            }
            initListener(it)
        }
        binding.root.post {
            checkPackage()
        }
    }

    private fun changeParams(size: Int) {
        val params = binding.packageRv.layoutParams as LinearLayout.LayoutParams
        params.height = if (size > 3) (28f.dip2px() * 3.5).toInt() else 28f.dip2px() * size
        binding.packageRv.layoutParams = params
    }

    private fun initListener(entity: PackageDialogEntity) {
        binding.downloadBtn.setOnClickListener {
            if (binding.noRemindAgainCb.isChecked) {
                saveRecord(entity)
            }
            val isAllPackageInstalled = isAllPackageInstalled(mAllInstalledPackages, entity)
            if (isAllPackageInstalled) {
                callBack?.onConfirm()
                dismissAllowingStateLoss()
            } else {
                var packageLink = getNotInstalledLink(entity)
                if (packageLink == null) {
                    packageLink = entity.links.find { it.buttonLink }
                }
                if (packageLink != null) {
                    LogUtils.uploadPackageCheck(
                        "pkg_check_pop_click",
                        "点击前往下载",
                        gameEntity,
                        packageLink.text,
                        packageLink.title,
                        "",
                        ""
                    )
                    DirectUtils.directToLinkPage(requireContext(), packageLink, "包名检测弹窗", "")
                }
            }
        }

        binding.cancelTv.setOnClickListener {
            if (entity.level != "HINT_SKIP") {
                callBack?.onConfirm()
            }
            if (binding.noRemindAgainCb.isChecked) {
                saveRecord(entity)
                LogUtils.uploadPackageCheck("pkg_check_pop_click", "不再提示", gameEntity, "", "", "", "")
            }
            dismissAllowingStateLoss()
        }
    }

    private fun saveRecord(entity: PackageDialogEntity) {
        if (entity.level == "OPTIONAL_CURRENT_HINT") {
            SPUtils.setBoolean("${Constants.SP_PACKAGE_CHECK}:${gameEntity?.id}", true)
        } else {
            SPUtils.setBoolean("${Constants.SP_PACKAGE_CHECK}:${gameEntity?.packageDialog?.id}", true)
        }
    }

    private fun checkPackage() {
        var index = 0
        mTotalWidth = (DisplayUtils.getScreenWidth() - 108f.dip2px()).toFloat()
        mDisposable = rxTimer(1) {
            gameEntity?.packageDialog?.detectionObjects?.let { objects ->
                if (objects.isNotEmpty()) {
                    val averageTime = if (objects.size == 1) {
                        mDuration
                    } else {
                        mDuration / objects.size
                    }
                    if (it != 0L && it % averageTime == 0L && index < objects.size) {
                        mAdapter?.notifyPackages()
                        binding.packageRv.smoothScrollToPosition(index)
                        index++
                    }
                }
            }

            if (it >= mDuration) {
                mDisposable?.dispose()
                binding.downloadBtn.isEnabled = true
                binding.downloadBtn.background = R.drawable.bg_notification_open_btn_style_2.toDrawable()
            }
        }
        val animator = ValueAnimator.ofInt(0, 100)
        animator.duration = mDuration.toLong()
        animator.interpolator = LinearInterpolator()
        animator.addUpdateListener {
            binding.progressBar.progress = it.animatedValue as Int
        }
        animator.start()
    }

    private fun getNotInstalledLink(packageDialogEntity: PackageDialogEntity): LinkEntity? {
        val links = LinkedHashSet<LinkEntity>()
        packageDialogEntity.detectionObjects.forEach { obj ->
            if (!checkDetectionsInstalled(mAllInstalledPackages, obj.packages)) {
                obj.assignDownload.forEach {
                    links.add(packageDialogEntity.links[it])
                }
            }
        }
        var link: LinkEntity? = null
        if (links.size > 1) {
            link = links.find { it.buttonLink } ?: links.toList()[0]
        } else if (links.size == 1) {
            link = links.toList()[0]
        }
        return link
    }

    override fun onStart() {
        super.onStart()
        val width = requireContext().resources.displayMetrics.widthPixels - 60F.dip2px()
        val height = ViewGroup.LayoutParams.WRAP_CONTENT
        requireDialog().window?.setLayout(width, height)
        requireDialog().setCanceledOnTouchOutside(true)
        DownloadManager.getInstance().addObserver(dataWatcher)
    }

    override fun onResume() {
        super.onResume()
        mAllInstalledPackages = PackageUtils.getInstalledPackages(HaloApp.getInstance().application, 0)
        gameEntity?.packageDialog?.let {
            if (isAllPackageInstalled(mAllInstalledPackages, it)) {
                callBack?.onConfirm()
                dismissAllowingStateLoss()
            }
        }
    }

    override fun onDestroyView() {
        super.onDestroyView()
        EventBus.getDefault().unregister(this)
        if (mDisposable?.isDisposed == false) {
            mDisposable?.dispose()
        }
        LogUtils.uploadPackageCheck("pkg_check_pop_click", "关闭弹窗", gameEntity, "", "", "", "")
        DownloadManager.getInstance().removeObserver(dataWatcher)
    }

    //安装、卸载事件
    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onEventMainThread(busFour: EBPackage) {
        if (busFour.isInstalledOrUninstalled()) {
            mAllInstalledPackages = PackageUtils.getInstalledPackages(HaloApp.getInstance().application, 0)
            mAdapter?.notifyDataSetChanged()
        }
    }

    inner class PackageCheckAdapter(val context: Context, val entities: ArrayList<DetectionObjectEntity>) :
        BaseRecyclerAdapter<RecyclerView.ViewHolder>(context) {
        private var index = -1

        fun notifyPackages() {
            index++
            notifyItemChanged(index)
        }

        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
            return PackageCheckViewHolder(parent.toBinding())
        }

        override fun getItemCount(): Int = entities.size

        override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
            if (holder is PackageCheckViewHolder) {
                val entity = entities[position]
                holder.binding.gameNameTv.text = entity.text
                if (position <= index) {
                    val isAllInstalled = checkDetectionsInstalled(mAllInstalledPackages, entity.packages)
                    if (isAllInstalled) {
                        holder.binding.statusTv.text = "已安装"
                        holder.binding.statusTv.setTextColor(ContextCompat.getColor(context, R.color.theme_font))
                    } else {
                        holder.binding.statusTv.text = "未安装"
                        holder.binding.statusTv.setTextColor(ContextCompat.getColor(context, R.color.theme_red))
                    }
                    holder.binding.statusTv.visibility = View.VISIBLE
                } else {
                    holder.binding.statusTv.visibility = View.GONE
                }
            }
        }
    }

    class PackageCheckViewHolder(val binding: PackageCheckItemBinding) :
        BaseRecyclerViewHolder<DetectionObjectEntity>(binding.root)

    companion object {
        @JvmStatic
        fun show(activity: AppCompatActivity, gameEntity: GameEntity, callBack: ConfirmListener) {
            val packageDialogEntity = gameEntity.packageDialog
            if (packageDialogEntity == null) {
                callBack.onConfirm()
                return
            }

            val allInstalledPackages = PackageUtils.getInstalledPackages(HaloApp.getInstance().application, 0)
            if (isAllPackageInstalled(allInstalledPackages, packageDialogEntity)) {
                callBack.onConfirm()
                return
            }

            val isChoose = SPUtils.getBoolean("${Constants.SP_PACKAGE_CHECK}:${packageDialogEntity.id}", false)
            if (packageDialogEntity.level == "OPTIONAL_HINT" && isChoose) {
                callBack.onConfirm()
                return
            }

            val isCurrentGameChoose = SPUtils.getBoolean("${Constants.SP_PACKAGE_CHECK}:${gameEntity.id}", false)
            if (packageDialogEntity.level == "OPTIONAL_CURRENT_HINT" && isCurrentGameChoose) {
                callBack.onConfirm()
                return
            }

            if (!activity.lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED)) return

            var dialogFragment =
                activity.supportFragmentManager.findFragmentByTag(PackageCheckDialogFragment::class.java.name) as? PackageCheckDialogFragment
            if (dialogFragment == null) {
                dialogFragment = PackageCheckDialogFragment()
                dialogFragment.gameEntity = gameEntity
                dialogFragment.callBack = callBack
                dialogFragment.show(activity.supportFragmentManager, PackageCheckDialogFragment::class.java.name)
            } else {
                dialogFragment.gameEntity = gameEntity
                dialogFragment.callBack = callBack
                val transaction: FragmentTransaction = activity.supportFragmentManager.beginTransaction()
                transaction.show(dialogFragment)
                transaction.commit()
            }
        }

        private fun checkDetectionsInstalled(
            allInstalledPackages: List<PackageInfo>,
            packages: ArrayList<String>
        ): Boolean {
            var isPackagesInstalled = false
            packages.forEach { packageName ->
                val isInstalled = allInstalledPackages.find { it.packageName == packageName } != null
                if (isInstalled) {
                    isPackagesInstalled = true
                    return@forEach
                }
            }
            return isPackagesInstalled
        }


        fun isAllPackageInstalled(
            allInstalledPackages: List<PackageInfo>,
            packageDialogEntity: PackageDialogEntity
        ): Boolean {
            var isAllInstalled = true
            packageDialogEntity.detectionObjects.forEach loop@{ obj ->
                if (!checkDetectionsInstalled(allInstalledPackages, obj.packages)) {
                    isAllInstalled = false
                    return isAllInstalled
                }
            }
            return isAllInstalled
        }
    }
}