package com.gh.gamecenter.common.view

import android.animation.AnimatorSet
import android.animation.ValueAnimator
import android.content.Context
import android.graphics.Typeface
import android.graphics.drawable.Drawable
import android.util.AttributeSet
import android.view.Gravity
import android.view.View
import android.view.ViewGroup
import android.view.animation.AccelerateDecelerateInterpolator
import android.widget.FrameLayout
import android.widget.LinearLayout
import android.widget.RadioButton
import android.widget.RadioGroup
import androidx.core.graphics.ColorUtils
import androidx.core.view.updateLayoutParams
import com.gh.gamecenter.common.R
import com.gh.gamecenter.common.utils.dip2px
import com.gh.gamecenter.common.utils.toColor
import com.gh.gamecenter.core.utils.doOnEnd
import com.gh.gamecenter.core.utils.doOnStart
import splitties.views.dsl.core.add
import kotlin.math.abs

class SegmentedFilterView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null): FrameLayout(context, attrs) {
    private var mItemWidth = LayoutParams.WRAP_CONTENT
    private var mItemHeight = LayoutParams.WRAP_CONTENT
    private var mItemPadding = 0
    private var mTextCheckedColor: Int = R.color.text_secondary.toColor(context)
    private var mTextDefaultColor: Int = R.color.text_tertiary.toColor(context)
    private var mTextSize = 10F
    private var mCheckedBoldText = false
    private var mContainerBackground: Drawable? = null
    private var mIndicatorBackground: Drawable? = null
    private var mAnimationDuration = 200
    private var mContainerPadding = 1F.dip2px()
    private var mCheckedPosition = -1
    private var mIsAnimating = false

    private lateinit var mContainer: FrameLayout
    private lateinit var mRadioGroup: RadioGroup
    private lateinit var mIndicator: View
    private var mCallback: OnCheckedCallback? = null

    private var mItemList = listOf<String>()

    init {
        initView(attrs)
    }

    fun setTextColor(checkedColor: Int, defaultColor: Int) {
        mTextCheckedColor = checkedColor
        mTextDefaultColor = defaultColor
        if (::mRadioGroup.isInitialized) {
            for (i in 0 until mRadioGroup.childCount) {
                val radioBtn = mRadioGroup.getChildAt(i) as RadioButton
                radioBtn.setTextColor(if (radioBtn.isChecked) mTextCheckedColor else mTextDefaultColor)
            }
        }
    }

    fun setContainerBackground(drawable: Drawable?) {
        background = drawable
    }

    fun setIndicatorBackground(drawable: Drawable?) {
        if (::mIndicator.isInitialized) {
            mIndicator.background = drawable
        }
    }

    private fun initView(attrs: AttributeSet?) {
        if (attrs != null) {
            val ta = context.obtainStyledAttributes(attrs, R.styleable.SegmentedFilterView)
            mContainerBackground =
                ta.getDrawable(R.styleable.SegmentedFilterView_containerBackground)
            mIndicatorBackground =
                ta.getDrawable(R.styleable.SegmentedFilterView_indicatorBackground)
            mContainerPadding = ta.getDimensionPixelSize(
                R.styleable.SegmentedFilterView_containerPadding,
                1F.dip2px()
            )
            mItemWidth = ta.getDimensionPixelSize(
                R.styleable.SegmentedFilterView_sfv_itemWidth,
                LayoutParams.WRAP_CONTENT
            )
            mItemHeight = ta.getDimensionPixelSize(
                R.styleable.SegmentedFilterView_sfv_itemHeight,
                LayoutParams.WRAP_CONTENT
            )
            mItemPadding = ta.getDimensionPixelSize(
                R.styleable.SegmentedFilterView_sfv_itemPadding,
                0
            )
            mAnimationDuration = ta.getInt(R.styleable.SegmentedFilterView_animationDuration, 200)
            mTextCheckedColor = ta.getColor(R.styleable.SegmentedFilterView_sfv_textCheckedColor, mTextCheckedColor)
            mTextDefaultColor = ta.getColor(R.styleable.SegmentedFilterView_sfv_textDefaultColor, mTextDefaultColor)
            mTextSize = ta.getFloat(R.styleable.SegmentedFilterView_sfv_textSize, 10F)
            mCheckedBoldText = ta.getBoolean(R.styleable.SegmentedFilterView_sfv_checked_bold_text, false)
            ta.recycle()
        }
        setPadding(mContainerPadding, mContainerPadding, mContainerPadding, mContainerPadding)
        if (mContainerBackground != null) background = mContainerBackground
        mContainer = FrameLayout(context)
        mIndicator = View(context).apply {
            visibility = View.GONE
            background = mIndicatorBackground
        }
        mRadioGroup = RadioGroup(context).apply {
            gravity = Gravity.CENTER
            orientation = LinearLayout.HORIZONTAL
        }
        add(mContainer, LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT))
        mContainer.add(mIndicator, LayoutParams(mItemWidth, mItemHeight))
        mContainer.add(
            mRadioGroup,
            LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)
        )
    }

    fun setItemList(itemList: List<String>, defaultCheckPosition: Int) {
        mItemList = itemList
        mRadioGroup.removeAllViews()
        addRadioButton()
        post {
            mIndicator.updateLayoutParams<ViewGroup.LayoutParams> {
                width = mRadioGroup.getChildAt(defaultCheckPosition)?.width ?: mItemWidth
            }
            mIndicator.visibility = View.VISIBLE
            setChecked(defaultCheckPosition)
        }
    }

    fun getItemList(): List<String> {
        return mItemList
    }

    fun performClick(position: Int) {
        if (position in 0 until mRadioGroup.childCount) {
            setChecked(position, true)
            mCallback?.onItemCheck(position)
        }
    }

    fun setChecked(position: Int, withAnimation: Boolean = false) {
        if (position in 0 until mRadioGroup.childCount && position != mCheckedPosition) {
            val checkedRb = mRadioGroup.getChildAt(position) as RadioButton
            val currentRb = mRadioGroup.getChildAt(mCheckedPosition) as? RadioButton
            if (!withAnimation) {
                mIndicator.x = checkedRb.x
                checkedRb.setTextColor(mTextCheckedColor)
                currentRb?.setTextColor(mTextDefaultColor)
                if (mCheckedBoldText) {
                    checkedRb.setTypeface(Typeface.DEFAULT, Typeface.BOLD)
                    currentRb?.setTypeface(Typeface.DEFAULT, Typeface.NORMAL)
                }
                mCheckedPosition = position
            }
            checkedRb.isChecked = true
        }
    }

    fun getCurrentPosition(): Int {
        var position = 0
        for (i in 0 until mRadioGroup.childCount) {
            val radioButton = mRadioGroup.getChildAt(i) as RadioButton
            if (radioButton.isChecked) {
                position = i
                break
            }
        }
        return position
    }

    fun setOnCheckedCallback(callback: OnCheckedCallback) {
        mCallback = callback
        mRadioGroup.setOnCheckedChangeListener { _, checkId ->
            val checkedRb = mRadioGroup.findViewById<RadioButton>(checkId)
            val checkedPosition = mRadioGroup.indexOfChild(checkedRb)
            val currentRb = mRadioGroup.getChildAt(mCheckedPosition) as? RadioButton
            if (checkId == checkedRb.id && checkedRb.x != mIndicator.x) {
                startAnimator(checkedPosition, checkedRb, currentRb)
                mCallback?.onItemCheck(checkedPosition)
            }
        }
    }

    private fun addRadioButton() {
        mItemList.forEachIndexed { _, item ->
            val radioButton = RadioButton(context).apply {
                background = null
                buttonDrawable = null
                text = item
                gravity = Gravity.CENTER
                textSize = mTextSize
                setTextColor(mTextDefaultColor)
                setPadding(mItemPadding, 0, mItemPadding, 0)
                isChecked = false
            }
            mRadioGroup.add(radioButton, LinearLayout.LayoutParams(mItemWidth, mItemHeight))
        }
    }

    private fun startAnimator(checkedPosition: Int, checkedRadioButton: RadioButton, currentRadioButton: RadioButton?) {
        if (mIsAnimating) return

        AnimatorSet().apply {
            val translateAnimator = ValueAnimator.ofFloat(mIndicator.x, checkedRadioButton.x).apply {
                interpolator = AccelerateDecelerateInterpolator()
                addUpdateListener {
                    mIndicator.x = it.animatedValue as Float
                }
            }
            val widthAnimator = ValueAnimator.ofInt(mIndicator.width, checkedRadioButton.width).apply {
                interpolator = AccelerateDecelerateInterpolator()
                addUpdateListener {
                    mIndicator.updateLayoutParams<ViewGroup.LayoutParams> { width = it.animatedValue as Int }
                }
            }
            val offset = abs(mIndicator.x - checkedRadioButton.x)
            val colorAnimator = ValueAnimator.ofFloat(0F, offset).apply {
                interpolator = AccelerateDecelerateInterpolator()
                addUpdateListener {
                    val offsetRatio = it.animatedValue as Float / offset
                    val toCheckedColor = ColorUtils.blendARGB(mTextDefaultColor, mTextCheckedColor, offsetRatio)
                    val toDefaultColor = ColorUtils.blendARGB(mTextCheckedColor, mTextDefaultColor, offsetRatio)
                    checkedRadioButton.setTextColor(toCheckedColor)
                    currentRadioButton?.setTextColor(toDefaultColor)
                }
            }
            doOnStart {
                mIsAnimating = true
            }
            doOnEnd {
                mIsAnimating = false
                mIndicator.x = checkedRadioButton.x
                checkedRadioButton.setTextColor(mTextCheckedColor)
                currentRadioButton?.setTextColor(mTextDefaultColor)
                if (mCheckedBoldText) {
                    checkedRadioButton.setTypeface(Typeface.DEFAULT, Typeface.BOLD)
                    currentRadioButton?.setTypeface(Typeface.DEFAULT, Typeface.NORMAL)
                }
                mCheckedPosition = checkedPosition
            }
            duration = mAnimationDuration.toLong()
            playTogether(translateAnimator, widthAnimator, colorAnimator)
        }.start()
    }

    fun interface OnCheckedCallback {
        fun onItemCheck(position: Int)
    }
}