package com.gh.gamecenter.forum.home.follow.fragment

import android.animation.ValueAnimator
import android.graphics.PointF
import android.os.Bundle
import android.view.View
import android.view.animation.Interpolator
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.LinearSmoothScroller
import androidx.recyclerview.widget.OrientationHelper
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.OnScrollListener
import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.fragment.LazyFragment
import com.gh.gamecenter.common.utils.dip2px
import com.gh.gamecenter.common.utils.visibleIf
import com.gh.gamecenter.databinding.FragmentFollowDynamicBinding
import com.gh.gamecenter.entity.FollowUserEntity
import com.gh.gamecenter.forum.home.follow.FollowDynamicActivity.Companion.KEY_SELECTED_POSITION
import com.gh.gamecenter.forum.home.follow.FollowDynamicActivity.Companion.KEY_USERS
import com.gh.gamecenter.forum.home.follow.adapter.FollowedHeaderAdapter
import com.gh.gamecenter.forum.home.follow.adapter.FollowedViewPagerAdapter
import com.gh.gamecenter.forum.home.follow.viewmodel.FollowDynamicViewModel
import com.gh.gamecenter.livedata.EventObserver
import kotlin.math.pow


class FollowDynamicFragment : LazyFragment() {

    private lateinit var binding: FragmentFollowDynamicBinding

    private val viewModel by activityViewModels<FollowDynamicViewModel>()

    private var selectedPosition = 0

    private val screenCenterX by lazy(LazyThreadSafetyMode.NONE) {
        resources.displayMetrics.widthPixels / 2
    }

    private val offsetX by lazy(LazyThreadSafetyMode.NONE) {
        screenCenterX - 32F.dip2px()
    }

    private val layoutManager by lazy(LazyThreadSafetyMode.NONE) {
        LinearLayoutManager(requireContext(), RecyclerView.HORIZONTAL, false)
    }

    private val helper by lazy {
        OrientationHelper.createHorizontalHelper(layoutManager)
    }

    private val followedAdapter by lazy {
        FollowedHeaderAdapter(requireContext(), object : FollowedHeaderAdapter.OnChildEventListener {
            override fun onViewItem(position: Int) {
                selectedPosition = position
                binding.viewPager.setCurrentItem(position, false)
                alignIndicator()
            }

            override fun onViewAll() = Unit

        })
    }

    private val dynamicListVpAdapter by lazy {
        FollowedViewPagerAdapter(this)
    }

    override fun getRealLayoutId(): Int = R.layout.fragment_follow_dynamic

    override fun onRealLayoutInflated(inflatedView: View) {
        binding = FragmentFollowDynamicBinding.bind(inflatedView)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val list = arguments?.getParcelableArrayList<FollowUserEntity>(KEY_USERS)
        if (list != null) {
            viewModel.addFirstPageUsers(list)
        }
        selectedPosition = arguments?.getInt(KEY_SELECTED_POSITION, 0) ?: 0

    }

    override fun onFragmentFirstVisible() {
        super.onFragmentFirstVisible()

        with(viewModel) {
            followedUsers.observe(viewLifecycleOwner, Observer { (isFirst, data) ->
                followedAdapter.submitList(data, selectedPosition)
                if (isFirst) {
                    scrollSelectedPositionToCenter(false)
                    startAnimation(true)
                }
                dynamicListVpAdapter.addData(data)
            })
        }

        binding.rvFollowedHeader.layoutManager = layoutManager
        binding.rvFollowedHeader.adapter = followedAdapter

        binding.viewPager.adapter = dynamicListVpAdapter
        binding.viewPager.offscreenPageLimit = 1
        binding.viewPager.setCurrentItem(selectedPosition, false)
        binding.viewPager.registerOnPageChangeCallback(object : OnPageChangeCallback() {
            override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) = Unit

            override fun onPageScrollStateChanged(state: Int) {
                super.onPageScrollStateChanged(state)
                if (state != 0) {
                    binding.ivIndicator.visibleIf(false)
                    followedAdapter.clearSelectedPosition()
                } else {
                    binding.ivIndicator.visibleIf(true)
                    followedAdapter.selectPosition(selectedPosition)
                }
            }

            override fun onPageSelected(position: Int) {
                if (selectedPosition != position) {
                    selectedPosition = position
                    followedAdapter.selectPosition(position)
                    scrollSelectedPositionToCenter(true)
                }
            }
        })

        with(viewModel) {
            finishAction.observe(viewLifecycleOwner, EventObserver {
                startAnimation(false)
                requireActivity().finish()
                requireActivity().overridePendingTransition(0, R.anim.no_anim)
            })
        }
    }

    private fun scrollSelectedPositionToCenter(isSmoothScroll: Boolean) {
        binding.rvFollowedHeader.clearOnScrollListeners()
        if (isSmoothScroll) {
            // 1. 如果当前 itemView 在屏幕内，则只需要直接将其滚动到中间即可
            if (!checkTargetViewIfExist()) {
                // 2. 如果当前itemView不在屏幕内，则需要先将 itemView 滚动到屏幕内，在将其滚到屏幕中间
                binding.rvFollowedHeader.addOnScrollListener(object : OnScrollListener() {
                    override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
                        super.onScrollStateChanged(recyclerView, newState)
                        if (newState == RecyclerView.SCROLL_STATE_IDLE) {
                            binding.rvFollowedHeader.clearOnScrollListeners()
                            checkTargetViewIfExist()
                        }
                    }
                })
                val vector = layoutManager.computeScrollVectorForPosition(selectedPosition) ?: PointF()
                val linearSmoothScroller = object : LinearSmoothScroller(requireContext()) {
                    override fun getHorizontalSnapPreference(): Int {
                        super.getHorizontalSnapPreference()
                        return if (vector.x > 0) SNAP_TO_END else SNAP_TO_START
                    }
                }
                linearSmoothScroller.targetPosition = selectedPosition
                layoutManager.startSmoothScroll(linearSmoothScroller)
            }

        } else {
            layoutManager.scrollToPositionWithOffset(selectedPosition, offsetX)
        }

        binding.rvFollowedHeader.addOnScrollListener(object : OnScrollListener() {

            override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
                super.onScrollStateChanged(recyclerView, newState)
                if (newState == RecyclerView.SCROLL_STATE_IDLE) {
                    alignIndicator()
                }
            }

            override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
                super.onScrolled(recyclerView, dx, dy)
                alignIndicator()
            }

        })
    }

    private fun alignIndicator() {
        val targetView = layoutManager.findViewByPosition(selectedPosition)
        if (targetView != null) {
            binding.ivIndicator.translationX = distanceToStart(targetView).toFloat()
        }
    }

    private fun checkTargetViewIfExist(): Boolean {
        val targetView = layoutManager.findViewByPosition(selectedPosition)
        if (targetView != null) {
            val distanceToCenter = distanceToCenter(targetView)
            if (distanceToCenter != 0) {
                binding.rvFollowedHeader.smoothScrollBy(distanceToCenter, 0)
            }
        }
        return targetView != null
    }

    private val easeOutInterpolator = Interpolator { input -> 1 - (1 - input).pow(2) }

    private fun startAnimation(isStart: Boolean) {
        val values = if (isStart) {
            floatArrayOf(ANIMATION_START_VALUE, ANIMATION_END_VALUE)
        } else {
            floatArrayOf(ANIMATION_END_VALUE, ANIMATION_START_VALUE)
        }
        val valueAnimator = ValueAnimator.ofFloat(*values)

        val followHeaderTranslationY =
            requireContext().resources.getDimensionPixelSize(R.dimen.follow_detail_header_translation_y)
        val dynamicListTranslationY =
            requireContext().resources.getDimensionPixelSize(R.dimen.follow_detail_content_translation_y)

        with(valueAnimator) {
            duration = ANIMATION_DURATION
            interpolator = easeOutInterpolator
            addUpdateListener {
                val value = it.animatedValue as Float
                val alphaEnd = 5F / 8F
                val alpha = if (value >= 0 && value <= alphaEnd) {
                    value / alphaEnd
                } else {
                    1F
                }
                binding.ivTopBackground.alpha = alpha
                binding.rvFollowedHeader.alpha = alpha
                binding.viewPager.alpha = alpha

                if (value >= 0.5F) {
                    binding.ivIndicator.alpha = (value - 0.5F) * 2
                } else {
                    binding.ivIndicator.alpha = 0F
                }

                binding.ivTopBackground.translationY = followHeaderTranslationY * (1 - value)
                binding.rvFollowedHeader.translationY = followHeaderTranslationY * (1 - value)
                binding.viewPager.translationY = dynamicListTranslationY * (1 - value)
                if (isStart && value == 1F) {
                    viewModel.startLoad()
                }

            }
            start()
        }
    }

    private fun distanceToCenter(targetView: View): Int {
        val childCenter = helper.getDecoratedStart(targetView) + helper.getDecoratedMeasurement(targetView) / 2
        val containerCenter = helper.startAfterPadding + helper.totalSpace / 2
        return childCenter - containerCenter
    }

    private fun distanceToStart(targetView: View): Int = distanceToCenter(targetView) + screenCenterX

    override fun onDarkModeChanged() {
        super.onDarkModeChanged()
        followedAdapter.notifyItemRangeChanged(0, followedAdapter.itemCount, "")
    }

    companion object {
        private const val ANIMATION_DURATION = 400L
        private const val ANIMATION_START_VALUE = 0F
        private const val ANIMATION_END_VALUE = 1F
    }
}