package com.gh.gamecenter.wrapper

import android.graphics.PorterDuff
import android.net.Uri
import android.os.Bundle
import android.os.Message
import android.text.SpannableStringBuilder
import android.text.TextUtils
import android.view.View
import android.widget.PopupWindow
import androidx.annotation.ColorRes
import androidx.constraintlayout.widget.ConstraintSet
import androidx.core.text.color
import androidx.core.view.doOnNextLayout
import androidx.fragment.app.Fragment
import androidx.viewpager2.adapter.FragmentStateAdapter
import com.ethanhua.skeleton.Skeleton
import com.ethanhua.skeleton.SkeletonScreen
import com.gh.common.iinterface.ISuperiorChain
import com.gh.common.prioritychain.BottomTabGuideHandler
import com.gh.common.prioritychain.GlobalPriorityChainHelper
import com.gh.common.prioritychain.PriorityChain
import com.gh.common.util.PackageHelper
import com.gh.gamecenter.R
import com.gh.gamecenter.ShellActivity
import com.gh.gamecenter.common.base.fragment.ToolbarFragment
import com.gh.gamecenter.common.callback.OnDoubleTapListener
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.eventbus.EBReuse
import com.gh.gamecenter.common.json.json
import com.gh.gamecenter.common.pagelevel.IPageLevelProvider
import com.gh.gamecenter.common.syncpage.SyncPageRepository
import com.gh.gamecenter.common.tracker.IBusiness
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.core.utils.DisplayUtils
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.databinding.FragmentMainBinding
import com.gh.gamecenter.databinding.PieceBottomTabBinding
import com.gh.gamecenter.entity.BottomTab
import com.gh.gamecenter.login.entity.UserInfoEntity
import com.halo.assistant.HaloApp
import com.lightgame.listeners.OnBackPressedListener
import org.greenrobot.eventbus.EventBus

class MainWrapperFragment : BaseBottomTabFragment<PieceBottomTabBinding>(), OnBackPressedListener, ISuperiorChain, IBusiness {
    private val mBinding by lazy { FragmentMainBinding.inflate(layoutInflater) }
    private var mViewModel: MainWrapperViewModel? = null
    private val mBottomTabList = ArrayList<BottomTab>()
    private val mAdapter by lazy { MainFragmentStateAdapter(this) }
    private var mTransparentStyle = false
    private var mInferiorChain: PriorityChain? = null
    private val mPriorityChain by lazy { PriorityChain { mInferiorChain?.start() } }
    private var mBottomTabGuideHandler: BottomTabGuideHandler? = null
    private var mBottomTabGuidePopupWindow: PopupWindow? = null
    private var mSkeletonScreen: SkeletonScreen? = null
    private val mCurrentFragment: Fragment?
        get() = try {
            childFragmentManager.findFragmentByTag(mAdapter.getFragmentTag(mBinding.viewPager.currentItem))
        } catch (e: Exception) {
            null
        }

    override fun getLayoutId(): Int = 0
    override fun getInflatedLayout(): View = mBinding.root
    override fun provideAdapter(): FragmentStateAdapter = mAdapter

    val currentItem: Int
        get() = mViewPager?.currentItem ?: 0

    val currentTab: BottomTab?
        get() = mBottomTabList.safelyGetInRelease(currentItem)

    override fun onCreate(savedInstanceState: Bundle?) {
        mViewModel = viewModelProviderFromParent(MainWrapperViewModel.Factory(HaloApp.getInstance()))
        super.onCreate(savedInstanceState)

        initSkeleton()

        mBinding.viewShadow.visibility = if (mIsDarkModeOn) View.GONE else View.VISIBLE
        buildPriorityChain()

        mViewModel?.bottomTabListLiveData?.observe(this) {
            mSkeletonScreen?.hide()
            mBottomTabList.clear()
            mBottomTabList.addAll(it)
            mViewPager?.offscreenPageLimit = it.size
            initBottomTab(mBottomTabList)
            showBottomTabGuideIfExists()
            mAdapter.submitList(mBottomTabList)
            val defaultBottomTabIndex = mViewModel!!.defaultBottomTabIndex
            val defaultBottomTab = mBottomTabList.getOrNull(defaultBottomTabIndex) ?: return@observe
            mViewPager?.doOnNextLayout {
                mViewModel?.handleBypassVisit(defaultBottomTab)
                setCurrentItem(defaultBottomTabIndex)
            }
        }
    }

    private fun buildPriorityChain() {
        mBottomTabGuideHandler = BottomTabGuideHandler(20)
        mPriorityChain.addHandler(mBottomTabGuideHandler!!)
    }

    private fun initSkeleton() {
        mSkeletonScreen = Skeleton.bind(mBinding.skeleton)
            .shimmer(true)
            .angle(Constants.SHIMMER_ANGLE)
            .color(com.gh.gamecenter.common.R.color.ui_skeleton_highlight)
            .duration(Constants.SHIMMER_DURATION)
            .maskWidth(Constants.MASK_WIDTH)
            .gradientCenterColorWidth(Constants.GRADIENT_CENTER_COLOR_WIDTH)
            .load(R.layout.fragment_main_skeleton)
            .show()
    }

    private fun showBottomTabGuideIfExists() {
        val guidePosition = mBottomTabList.indexOfFirst { it.guide != null }
        if (guidePosition != -1) {
            val bottomTab = mBottomTabList[guidePosition]
            val guide = bottomTab.guide!!
            guide.bottomTabId = bottomTab.id
            val screenWidth = DisplayUtils.getScreenWidth(requireActivity())
            val bottomTabWidth = screenWidth / mBottomTabList.size
            val isRightPosition = (guidePosition * 2 + 1) > mBottomTabList.size
            val isCenterPosition = (guidePosition * 2 + 1) == mBottomTabList.size
            val triangleTransX = bottomTabWidth * guidePosition + bottomTabWidth / 2F - BOTTOM_TAB_GUIDE_TRIANGLE_OFFSET_DP.dip2px()
            val guideTransX = if (isCenterPosition) {
                0F
            } else if (isRightPosition) {
                -(screenWidth - triangleTransX - 22F.dip2px())
            } else {
                triangleTransX - 12F.dip2px()
            }
            val restWidth = if (isCenterPosition) {
                screenWidth.toFloat()
            } else if (isRightPosition) {
                screenWidth + guideTransX
            } else {
                screenWidth - guideTransX
            }

            mBottomTabGuideHandler?.doPreProcess(
                true,
                requireActivity(),
                mBaseHandler,
                mViewPager,
                guide,
                triangleTransX,
                guideTransX,
                restWidth,
                isCenterPosition,
                isRightPosition
            )
        } else {
            mBottomTabGuideHandler?.doPreProcess(false)
        }
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        mViewModel?.tabSelectedLiveData?.observe(viewLifecycleOwner) {
            val selectedTab = it.getContentWithHandled()
            if (selectedTab is MainSelectedEvent.SelectedTab && selectedTab.bottomTabIndex != -1) {
                setCurrentItem(selectedTab.bottomTabIndex)
            }
        }

        mViewModel?.realNameInfoUpdateLiveData?.observe(viewLifecycleOwner) {
            updateRealNameErrorContainer()
        }

        PackageHelper.installedPackageApiSwitchStatusLiveData.observe(viewLifecycleOwner) {
            if (it) {
                showInstallApiHintView(mBinding)
                SensorsBridge.trackInstalledListPermissionsDialogShow()
            } else {
                mBinding.installApiContainer.visibility = View.GONE
            }
        }
    }

    fun setCurrentItem(page: Int) {
        if (page < mBottomTabList.size) {
            mViewPager?.setCurrentItem(page, false)
            onPageSelected(page)
            changeBottomTabStyle(page)
            trackBottomTabEvent(page)
        }
    }

    fun setCurrentItem(type: String) {
        val toCheck = mBottomTabList.indexOfFirst { type == it.link?.type }
        if (toCheck != -1) {
            setCurrentItem(toCheck)
        }
    }

    override fun provideBottomTabView(position: Int, bottomTab: BottomTab): View {
        return super.provideBottomTabView(position, bottomTab).apply {
            setOnTouchListener(object : OnDoubleTapListener(requireContext()) {
                override fun onDoubleTap() {
                    mViewModel?.bottomDoubleTabAction?.postValue(bottomTab)
                }
            })
        }
    }

    override fun onPause() {
        super.onPause()
        SyncPageRepository.clearSyncData()
        GlobalPriorityChainHelper.unregisterInferiorChain(mPriorityChain)
    }

    override fun onResume() {
        super.onResume()
        GlobalPriorityChainHelper.registerInferiorChain(mPriorityChain)
    }

    override fun handleOnClick(view: View?): Boolean {
        val toCheck = mBottomTabContainer?.indexOfChild(view) ?: return true
        val bottomTab = mBottomTabList.getOrNull(toCheck)
        if (bottomTab?.guide != null) {
            dismissBottomTabGuide()
        }
        bottomTab?.let {
            mViewModel?.handleBypassVisit(it)
        }
        playTabAnimation(toCheck)
        changeBottomTabStyle(toCheck)
        EventBus.getDefault().post(EBReuse(Constants.FINISH_PULL_DOWN_PUSH))
        trackBottomTabEvent(toCheck)
        return super.handleOnClick(view)
    }

    private fun trackBottomTabEvent(position: Int) {
        SensorsBridge.trackEvent("HomeBottomTabSelect", json {
            "tab_content" to mBottomTabList.safelyGetInRelease(position)?.name
            "link_type" to mBottomTabList.safelyGetInRelease(position)?.link?.type
            "link_id" to mBottomTabList.safelyGetInRelease(position)?.link?.link
            "link_text" to mBottomTabList.safelyGetInRelease(position)?.link?.text
            "position" to position
        })
    }

    override fun onHandleBackPressed(): Boolean {
        if (!isAdded) return false

        val currentFragment = mCurrentFragment
        if (currentFragment != null && currentFragment is ToolbarFragment) {
            return currentFragment.onBackPressed()
        }
        return false
    }

    private fun playTabAnimation(toCheck: Int) {
        mBottomTabBindingList.forEachIndexed { index, binding ->
            if (index == toCheck) {
                playAnimation(binding)
            } else {
                stopAnimation(binding)
            }
        }
    }

    private fun playAnimation(binding: PieceBottomTabBinding) {
        binding.tabIv.visibility = View.INVISIBLE
        binding.tabLottie.run {
            visibility = View.VISIBLE
            playAnimation()
            doOnAnimationEnd {
                visibility = View.GONE
                binding.tabIv.visibility = View.VISIBLE
            }
        }
    }

    private fun stopAnimation(binding: PieceBottomTabBinding) {
        binding.tabIv.visibility = View.VISIBLE
        binding.tabLottie.visibility = View.GONE
    }

    private fun changeBottomTabStyle(toCheck: Int) {
        if (mBottomTabList.safelyGetInRelease(toCheck)?.isTransparentStyle == true) {
            if (!mTransparentStyle) {
                ConstraintSet().apply {
                    clone(mBinding.root)
                    clear(mBinding.viewPager.id, ConstraintSet.BOTTOM)
                    connect(mBinding.viewPager.id, ConstraintSet.BOTTOM, ConstraintSet.PARENT_ID, ConstraintSet.BOTTOM)
                }.applyTo(mBinding.root)
            }

            mTransparentStyle = true
            mBinding.viewShadow.visibility = View.GONE
            mBottomTabContainer?.setBackgroundColor(com.gh.gamecenter.common.R.color.transparent.toColor(requireContext()))
            changeTabImageColor(com.gh.gamecenter.common.R.color.text_A1A5B7, PorterDuff.Mode.SRC_ATOP, toCheck)
        } else {
            if (mTransparentStyle) {
                ConstraintSet().apply {
                    clone(mBinding.root)
                    clear(mBinding.viewPager.id, ConstraintSet.BOTTOM)
                    connect(mBinding.viewPager.id, ConstraintSet.BOTTOM, mBinding.bottomTabContainer.id, ConstraintSet.TOP)
                }.applyTo(mBinding.root)
            }

            mTransparentStyle = false
            mBinding.viewShadow.visibility = if (mIsDarkModeOn) View.GONE else View.VISIBLE
            mBottomTabContainer?.setBackgroundColor(com.gh.gamecenter.common.R.color.ui_surface.toColor(requireContext()))
            changeTabImageColor(
                if (mIsDarkModeOn) com.gh.gamecenter.common.R.color.text_A1A5B7 else com.gh.gamecenter.common.R.color.text_50556B,
                if (mIsDarkModeOn) PorterDuff.Mode.SRC_ATOP else PorterDuff.Mode.DST,
                toCheck
            )
        }
        changeTabTextColor(toCheck)
    }

    private fun changeTabImageColor(@ColorRes colorRes: Int, mode: PorterDuff.Mode, toCheck: Int) {
        mBottomTabBindingList.forEachIndexed { index, binding ->
            if (index != toCheck) {
                binding.tabIv.setColorFilter(colorRes.toColor(requireContext()), mode)
            } else {
                binding.tabIv.colorFilter = null
            }
        }
    }

    private fun changeTabTextColor(toCheck: Int) {
        mBottomTabBindingList.forEachIndexed { index, binding ->
            val isChecked = index == toCheck
            val unselectColor =
                if (mBottomTabList.safelyGetInRelease(toCheck)?.isTransparentStyle == true) com.gh.gamecenter.common.R.color.text_A1A5B7 else com.gh.gamecenter.common.R.color.tab_text_unselect
            binding.tabTv.setTextColor((if (isChecked) com.gh.gamecenter.common.R.color.text_theme else unselectColor).toColor(requireContext()))
        }
    }

    override fun onPageSelected(position: Int) {
        super.onPageSelected(position)
        mBottomTabList.forEachIndexed { index, bottomTab ->
            if (index < mBottomTabBindingList.size && bottomTab.iconSelector == 0) {
                ImageUtils.picasso
                    .load(Uri.parse(if (position == index) bottomTab.iconSelect else bottomTab.iconUnselect))
                    .placeholder(com.gh.gamecenter.common.R.drawable.occupy)
                    .into(mBottomTabBindingList[index].tabIv)
            }
        }

        // 更新当前页面的 PageLevel tab position 信息
        if (activity is IPageLevelProvider) {
            // 更新底部 tab 的 position
            (activity as IPageLevelProvider).getPageLevel().bottomTabPosition = position

            // 若选中的底部 tab 对应的 fragment 不为 BaseTabWrapperFragment，则清空顶部 tab 的 position 信息
            val currentFragment = childFragmentManager.findFragmentByTag(mAdapter.getFragmentTag(position))
            if (currentFragment !is BaseTabWrapperFragment) {
                (activity as IPageLevelProvider).getPageLevel().updateTopTabPosition(position, -1)
            }
        }
    }

    private fun updateRealNameErrorContainer() {
        val deviceCertificationInfoString =
            SPUtils.getString(Constants.SP_DEVICE_CERTIFICATION_PREFIX + HaloApp.getInstance().gid)

        // 未点过关闭按钮并且处于实名认证失败状态的，显示提示 view
        if (!SPUtils.getBoolean(Constants.SP_REALNAME_ERROR_HINT_IGNORED)
            && !TextUtils.isEmpty(deviceCertificationInfoString)
        ) {
            val entity: UserInfoEntity? = deviceCertificationInfoString.toObject()
            if (entity?.idCard != null && entity.idCard!!.status == 2) {
                mBinding.realNameErrorContainer.visibility = View.VISIBLE
                mBinding.realNameErrorCloseIv.enlargeTouchArea(100)
                mBinding.realNameErrorCloseIv.setOnClickListener {
                    SPUtils.setBoolean(Constants.SP_REALNAME_ERROR_HINT_IGNORED, true)
                    mBinding.realNameErrorContainer.visibility = View.GONE
                }
                mBinding.realNameErrorContainer.setOnClickListener {
                    startActivity(ShellActivity.getIntent(requireActivity(), ShellActivity.Type.REAL_NAME_INFO, null))
                }
            } else {
                mBinding.realNameErrorContainer.visibility = View.GONE
            }
        }
    }

    private fun showInstallApiHintView(binding: FragmentMainBinding) {
        val contentText = SpannableStringBuilder()
            .color(com.gh.gamecenter.common.R.color.text_theme.toColor(requireContext())) { append("您未授予已安装列表权限，可能导致无法安装及更新建议开启权限！") }
//            .color(R.color.secondary_red.toColor(requireContext())) { append("导致无法安装及更新") }
//            .color(R.color.text_theme.toColor(requireContext())) { append("建议开启权限！") }

        binding.installApiContainer.visibility = View.VISIBLE
        binding.installApiContainer.setOnClickListener {
            // do nothing
        }
        binding.installApiCloseIv.enlargeTouchArea()
        binding.installApiContentTv.text = contentText
        binding.installApiCloseIv.setOnClickListener {
            binding.installApiContainer.visibility = View.GONE
            SensorsBridge.trackInstalledListPermissionsClick("关闭")
        }
        binding.installApiBtn.setOnClickListener {
            SensorsBridge.trackInstalledListPermissionsClick("去开启")

            val callbackClosure: (Boolean) -> Unit = { isGranted ->
                if (isGranted) {
                    binding.installApiContainer.visibility = View.GONE
                }
            }

            PackageHelper.showGetInstallAppsListDialogAndRequestPermissionIfNeeded(
                activity = requireActivity(),
                ignorePermanentlyDenied = false,
                resultClosure = callbackClosure
            )
        }
    }

    override fun onDarkModeChanged() {
        super.onDarkModeChanged()
        changeBottomTabStyle(mBinding.viewPager.currentItem)
    }

    override fun registerInferiorChain(chain: PriorityChain) {
        mInferiorChain = chain
        if (mPriorityChain.isHandlerQueueEmpty()) {
            mInferiorChain?.resume()
        }
    }

    override fun unregisterInferiorChain(chain: PriorityChain) {
        if (mInferiorChain == chain) {
            mInferiorChain = null
        }
    }

    private fun dismissBottomTabGuide() {
        mBaseHandler.post {
            mBottomTabGuideHandler?.dismiss()
            if (mBottomTabGuidePopupWindow?.isShowing == true) {
                mBottomTabGuidePopupWindow?.dismiss()
            }
        }
    }

    override fun handleMessage(msg: Message?) {
        super.handleMessage(msg)
        if (msg?.what == BottomTabGuideHandler.KEY_BOTTOM_TAB_GUIDE_AUTO_DISMISS) {
            dismissBottomTabGuide()
        }
    }

    companion object {
        const val BOTTOM_TAB_GUIDE_TRIANGLE_OFFSET_DP = 5F
    }

    override fun getBusinessId(): Pair<String, String> = (mCurrentFragment as? IBusiness)?.getBusinessId() ?: Pair("", "")
}
