package com.gh.gamecenter.home.custom

import android.animation.AnimatorSet
import android.animation.ObjectAnimator
import android.app.Dialog
import android.content.DialogInterface
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Build
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.Window
import android.view.animation.PathInterpolator
import android.widget.RelativeLayout
import com.therouter.TheRouter
import com.gh.common.exposure.ExposureManager
import com.gh.common.exposure.ExposureTraceUtils
import com.gh.common.util.DirectUtils
import com.gh.common.util.LogUtils
import com.gh.gamecenter.common.base.fragment.BaseDialogFragment
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.common.exposure.ExposureSource
import com.gh.gamecenter.common.utils.ImageUtils
import com.gh.gamecenter.common.utils.SensorsBridge
import com.gh.gamecenter.common.utils.dip2px
import com.gh.gamecenter.common.utils.tryWithDefaultCatch
import com.gh.gamecenter.common.view.WrapContentDraweeView
import com.gh.gamecenter.core.provider.IFloatingWindowProvider
import com.gh.gamecenter.core.utils.DisplayUtils
import com.gh.gamecenter.core.utils.addListener
import com.gh.gamecenter.databinding.DialogWelcomeCustomBinding
import com.gh.gamecenter.feature.entity.PageLocation
import com.gh.gamecenter.feature.entity.WelcomeDialogEntity
import com.gh.gamecenter.feature.exposure.ExposureEvent
import com.gh.gamecenter.feature.exposure.ExposureType
import com.halo.assistant.HaloApp

class CustomWelcomeDialogFragment : BaseDialogFragment() {

    private var mWelcomeEntity: WelcomeDialogEntity? = null
    private var mPageLocation: PageLocation? = null

    private lateinit var mBinding: DialogWelcomeCustomBinding

    private var mShowEnterAnimation: Boolean = false
    private var mShowExitAnimation: Boolean = false

    // 触发此 dialogFragment 的 fragment，可能为空
    private var mTriggerFragment: CustomPageFragment? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        mWelcomeEntity = arguments?.getParcelable(TAG)
        mPageLocation = arguments?.getParcelable(PageLocation::class.java.simpleName)
    }

    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        // the content
        val root = RelativeLayout(activity)
        root.layoutParams =
            ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)

        // creating the fullscreen dialog
        val dialog = Dialog(requireActivity())
        dialog.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
        dialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
        dialog.setContentView(root)
        if (mShowEnterAnimation) {
            dialog.window?.setDimAmount(0F)
        } else {
            dialog.window?.setDimAmount(0.5F)
        }
        dialog.window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
        return dialog
    }

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
        mBinding = DialogWelcomeCustomBinding.inflate(inflater, container, false)

        mBinding.ivOpeningCover.setOnClickListener {
            HaloApp.put(Constants.WELCOME_DIALOG_ID, mWelcomeEntity?.id)
            HaloApp.put(Constants.WELCOME_DIALOG_LINK_TITLE, mWelcomeEntity?.text)
            LogUtils.uploadWelcomeDialog(
                "click",
                mWelcomeEntity?.id,
                mWelcomeEntity?.id,
                mWelcomeEntity?.type,
                mWelcomeEntity?.text
            )
            SensorsBridge.trackSuspendedWindowClick(
                "弹窗",
                "跳转",
                "自定义页面",
                bottomTab = mPageLocation?.bottomTab ?: "",
                multiTabId = mPageLocation?.severalTabPageId ?: "",
                multiTabName = mPageLocation?.severalTabPageName ?: "",
                position = mPageLocation?.tabPosition ?: -1,
                tabContent = mPageLocation?.tabContent ?: "",
                customPageId = mPageLocation?.pageId ?: "",
                customPageName = mPageLocation?.pageName ?: "",
                linkId = mWelcomeEntity?.link ?: "",
                linkType = mWelcomeEntity?.type ?: "",
                linkText = mWelcomeEntity?.text ?: ""
            )
            val clickEvent = ExposureEvent.createEventWithSourceConcat(
                null,
                mWelcomeEntity?.traceEvent?.source ?: emptyList(),
                listOf(ExposureSource("弹窗")),
                eTrace = ExposureTraceUtils.appendTrace(mWelcomeEntity?.traceEvent),
                event = ExposureType.CLICK
            )
            if (mWelcomeEntity?.type != "game") {
                ExposureManager.log(clickEvent)
            }

            mWelcomeEntity?.let {
                DirectUtils.directToLinkPage(requireContext(), it, EntranceConsts.ENTRANCE_WELCOME, "", clickEvent)
                if (mShowEnterAnimation) {
                    val floatingWindowProvider = TheRouter.get(IFloatingWindowProvider::class.java)

                    floatingWindowProvider?.logWindowClicked(
                        action = "点击弹窗跳转页面",
                        windowId = mWelcomeEntity?.floatingWindowId ?: "",
                        source = "首页",
                        gameId = "",
                        gameName = "",
                        linkId = mWelcomeEntity?.link ?: "",
                        linkType = mWelcomeEntity?.type ?: "",
                        linkText = mWelcomeEntity?.text ?: ""
                    )
                }
            }

            dismissAllowingStateLoss()
        }

        mBinding.ivOpeningCover.setFixedWidth(300)
        mBinding.ivOpeningCover.registerLoadingCallback(object : WrapContentDraweeView.LoadingCallback {
            override fun loaded() {
                mBinding.root.post {
                    if (mBinding.ivOpeningCover.measuredHeight > mBinding.root.resources.displayMetrics.heightPixels * .8) {
                        mBinding.ivCloseBackup.visibility = View.VISIBLE
                    } else {
                        mBinding.ivClose.visibility = View.VISIBLE
                    }

                    if (mShowEnterAnimation) {
                        performAnimation(true)
                    }
                }

                mBinding.ivOpeningCover.registerLoadingCallback(null)
            }
        })

        mBinding.ivCloseBackup.setOnClickListener {
            val floatingWindowProvider = TheRouter.get(IFloatingWindowProvider::class.java)

            // 来源 fragment 是否不可见
            if (mTriggerFragment?.isCurrentlyVisible() == false) {
                mShowExitAnimation = false
            } else {
                floatingWindowProvider?.showHiddenWindow(requireActivity())
            }

            if (mShowExitAnimation) {
                dismissWithAnimation()
            } else {
                dismissAllowingStateLoss()
            }

            SensorsBridge.trackSuspendedWindowClick(
                "弹窗",
                "关闭",
                "自定义页面",
                bottomTab = mPageLocation?.bottomTab ?: "",
                multiTabId = mPageLocation?.severalTabPageId ?: "",
                multiTabName = mPageLocation?.severalTabPageName ?: "",
                position = mPageLocation?.tabPosition ?: -1,
                tabContent = mPageLocation?.tabContent ?: "",
                customPageId = mPageLocation?.pageId ?: "",
                customPageName = mPageLocation?.pageName ?: "",
                linkId = mWelcomeEntity?.link ?: "",
                linkType = mWelcomeEntity?.type ?: "",
                linkText = mWelcomeEntity?.text ?: ""
            )
        }
        mBinding.ivClose.setOnClickListener { mBinding.ivCloseBackup.performClick() }
        ImageUtils.displayWithoutMemoryCache(mBinding.ivOpeningCover, mWelcomeEntity?.icon)

        // 弹起启动弹窗时，把右下角悬浮窗置为隐藏
        val floatingWindowProvider = TheRouter.get(IFloatingWindowProvider::class.java)

        floatingWindowProvider?.hideWindow(requireActivity())

        return mBinding.root
    }

    override fun dismissAllowingStateLoss() {
        tryWithDefaultCatch {
            super.dismissAllowingStateLoss()
        }
    }

    override fun dismiss() {
        tryWithDefaultCatch {
            super.dismiss()
        }
    }

    private var onDismissListener: (() -> Unit)? = null

    fun setDismissListener(listener: () -> Unit) {
        onDismissListener = listener
    }

    /**
     * 显示动画
     * @param isEnterAnimation 是否为进入动画
     */
    private fun performAnimation(isEnterAnimation: Boolean) {
        // 贝塞尔曲线需要 Android 版本大于 Android 5.0
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            val screenWidth = DisplayUtils.getScreenWidth(requireActivity())
            val screenHeight = DisplayUtils.getScreenHeight(requireActivity())
            val statusBarHeight = DisplayUtils.getStatusBarHeight(requireContext().resources)

            // 最大宽度为 300dp
            val maxWidth = 300F
            val initialWidth = 1F

            val containerWidth = mBinding.container.width
            val containerHeight = containerWidth / mBinding.ivOpeningCover.aspectRatio + 54F.dip2px()

            val location = IntArray(2)
            mBinding.container.getLocationOnScreen(location)

            val xOffsetToTheScreen = location[0]
            // 由于显示的时机问题，mBinding.container.getLocationOnScreen(location) 获取到的纵座标不一定是真实在屏幕的高度，这里手动计算
            val yOffsetToTheScreen = (screenHeight - containerHeight) / 2 + statusBarHeight

            val scaleRatio = initialWidth / maxWidth
            // 获取动画原点的 X, Y 座标，由于 scale 会变化，所以需要结合 scale 进行计算
            val initialX = (screenWidth - 40F.dip2px() - xOffsetToTheScreen) - (containerWidth * (1 - scaleRatio)) / 2
            val dist = screenHeight - (mTriggerFragment?.getFloatingViewY() ?: 0)
            val initialY =
                (screenHeight - dist - yOffsetToTheScreen) - (containerHeight * (1 - scaleRatio)) / 2 + statusBarHeight

            val startX = if (isEnterAnimation) initialX else 0F
            val startY = if (isEnterAnimation) initialY else 0F

            val startScale = if (isEnterAnimation) scaleRatio else 1F
            val endScale = if (isEnterAnimation) 1F else scaleRatio

            val endX = if (isEnterAnimation) 0F else initialX
            val endY = if (isEnterAnimation) 0F else initialY

            val enteringTranslationXInterpolator = PathInterpolator(0.4F, 1.6F, 0.4F, 1.24F)
            val enteringTranslationYInterpolator = PathInterpolator(0.4F, 1.8F, 0.4F, 1.24F)
            val exitingTranslationXInterpolator = PathInterpolator(0.6F, -0.24F, 0.6F, -0.6F)
            val exitingTranslationYInterpolator = PathInterpolator(0.6F, -0.24F, 0.6F, -0.2F)

            val enteringScaleInterpolator = PathInterpolator(0.61F, 1F, 0.88F, 1F)
            val exitingScaleInterpolator = PathInterpolator(0.12F, 0F, 0.39F, 0F)

            val translationXAnimator =
                ObjectAnimator.ofFloat(mBinding.container, "translationX", startX, endX).apply {
                    interpolator =
                        if (isEnterAnimation) enteringTranslationXInterpolator else exitingTranslationXInterpolator
                }
            val translationYAnimator =
                ObjectAnimator.ofFloat(mBinding.container, "translationY", startY, endY).apply {
                    interpolator =
                        if (isEnterAnimation) enteringTranslationYInterpolator else exitingTranslationYInterpolator
                }

            val scaleXAnimator = ObjectAnimator.ofFloat(mBinding.container, "scaleX", startScale, endScale).apply {
                addUpdateListener {
                    val dimAmount = it.animatedValue as Float / 2
                    dialog?.window?.setDimAmount(dimAmount)

                    // 避免与原有悬浮窗重叠，退出动画执行到 95% 进度后隐藏
                    if (!isEnterAnimation && (it.animatedValue as Float) < 0.05F) {
                        mBinding.container.visibility = View.GONE
                    } else {
                        mBinding.container.visibility = View.VISIBLE
                    }
                }
            }
            val scaleYAnimator = ObjectAnimator.ofFloat(mBinding.container, "scaleY", startScale, endScale)
            val scaleAnimatorSet = AnimatorSet().apply {
                playTogether(scaleXAnimator, scaleYAnimator)
                interpolator = if (isEnterAnimation) enteringScaleInterpolator else exitingScaleInterpolator
            }

            mBinding.root.pivotX = mBinding.root.width / 2F
            mBinding.root.pivotY = mBinding.root.height / 2F

            dialog?.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))

            val translationAnimatorSet = AnimatorSet().apply {
                playTogether(translationXAnimator, translationYAnimator)
            }

            AnimatorSet().apply {
                playTogether(
                    scaleAnimatorSet,
                    translationAnimatorSet
                )
                addListener(
                    onStart = {
                        mBinding.container.isClickable = false
                        mBinding.ivOpeningCover.isClickable = false
                        mBinding.ivClose.isClickable = false
                    },
                    onEnd = {
                        if (!isEnterAnimation) {
                            dismissAllowingStateLoss()
                        }
                        mBinding.container.isClickable = true
                        mBinding.ivOpeningCover.isClickable = true
                        mBinding.ivClose.isClickable = true
                    }
                )
                duration = ANIMATION_DURATION
            }.start()
        }
    }

    private fun dismissWithAnimation() {
        onDismissListener?.invoke()
        performAnimation(false)
    }

    override fun onDismiss(dialog: DialogInterface) {
        super.onDismiss(dialog)

        LogUtils.uploadWelcomeDialog(
            "close",
            mWelcomeEntity?.id,
            mWelcomeEntity?.id,
            mWelcomeEntity?.type,
            mWelcomeEntity?.text
        )

        onDismissListener?.invoke()
    }

    companion object {
        const val TAG = "custom_welcome_dialog"

        const val ANIMATION_DURATION = 800L

        @JvmStatic
        fun getInstance(
            welcomeEntity: WelcomeDialogEntity?,
            withAnimation: Boolean = false,
            triggerFragment: CustomPageFragment? = null,
            hasAnimation: Boolean,
            pageLocation: PageLocation
        ) = CustomWelcomeDialogFragment().apply {
            arguments = Bundle().apply {
                putParcelable(TAG, welcomeEntity)
                putParcelable(PageLocation::class.java.simpleName, pageLocation)
            }
            LogUtils.uploadWelcomeDialog(
                "show",
                welcomeEntity?.id,
                welcomeEntity?.id,
                welcomeEntity?.type,
                welcomeEntity?.text
            )

            mTriggerFragment = triggerFragment

            // 低于 Android 5.0 禁用动画，因为贝塞尔曲线需要 5.0+ 支持
            mShowEnterAnimation = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP || !hasAnimation) {
                false
            } else {
                withAnimation
            }

            mShowExitAnimation = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
                false
            } else {
                withAnimation || welcomeEntity?.shouldShowExitAnimation == true
            }

            SensorsBridge.trackSuspendedWindowShow(
                "弹窗",
                "自定义页面",
                bottomTab = pageLocation.bottomTab,
                multiTabId = pageLocation.severalTabPageId,
                multiTabName = pageLocation.severalTabPageName,
                position = pageLocation.tabPosition,
                tabContent = pageLocation.tabContent,
                customPageId = pageLocation.pageId,
                customPageName = pageLocation.pageName,
                linkId = welcomeEntity?.link ?: "",
                linkType = welcomeEntity?.type ?: "",
                linkText = welcomeEntity?.text ?: "",
            )
            ExposureManager.log(
                ExposureEvent.createEventWithSourceConcat(
                    null,
                    welcomeEntity?.traceEvent?.source ?: emptyList(),
                    listOf(ExposureSource("弹窗")),
                    eTrace = ExposureTraceUtils.appendTrace(welcomeEntity?.traceEvent)
                )
            )
        }
    }
}