package com.remax.visualnovel.ui.chat.ui.expandableSelector

import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.ObjectAnimator
import android.animation.ValueAnimator
import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
import android.view.animation.AccelerateDecelerateInterpolator
import android.widget.LinearLayout
import androidx.core.view.isVisible
import com.remax.visualnovel.R
import com.remax.visualnovel.databinding.LayoutExpandSelectViewBinding
import com.remax.visualnovel.databinding.LayoutItemChatModeBinding
import com.remax.visualnovel.entity.response.ChatMode
import com.remax.visualnovel.utils.spannablex.utils.dp


class ExpandChatModeSelectView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : LinearLayout(context, attrs, defStyleAttr) {

    private lateinit var mBinding: LayoutExpandSelectViewBinding

    private var isExpanded = false
    private var animationDuration = 300
    private var items: List<ChatMode> = emptyList()

    private var mEventListener: IEventListener? = null
    interface IEventListener {
        fun onItemSelected(position: Int, item: ChatMode)
        fun onExpanded(isExpanded: Boolean)
    }

    fun setOnEventListener(listener: IEventListener) {
        this.mEventListener = listener
    }

    init {
        initView(context, attrs)
    }

    private fun initView(context: Context, attrs: AttributeSet?) {
        mBinding = LayoutExpandSelectViewBinding.inflate(LayoutInflater.from(context), this, true)
        mBinding.itemsContainer.setBackgroundResource(R.drawable.bg_expand_view_items)
        setupAttributes(attrs)
        setupClickListeners()
    }

    private fun setupAttributes(attrs: AttributeSet?) {
        attrs?.let {
            val typedArray = context.obtainStyledAttributes(it, R.styleable.ExpandableSelector)
            val title = typedArray.getString(R.styleable.ExpandableSelector_titleText)
            title?.let { mBinding.titleText.text = it }
            animationDuration = typedArray.getInt(R.styleable.ExpandableSelector_animationDuration, 300)
            typedArray.recycle()
        }
    }

    private fun setupClickListeners() {
        mBinding.titleLayout.setOnClickListener { toggle() }
    }


    fun setTitleIcon(resId: Int) {
        mBinding.icon.setImageResource(resId)
    }

    fun setTitleText(titleRes: Int) {
        mBinding.titleText.text = context.resources.getString(titleRes)
    }

    fun setItems(newItems: List<ChatMode>) {
        items = newItems
        updateItemsView()
    }



    private fun updateItemsView() {
        mBinding.itemsContainer.removeAllViews()

        items.forEachIndexed { index, item ->
            val itemView = createChatModeItemView(item, index)
            mBinding.itemsContainer.addView(itemView)

            if (index < items.size - 1) {
                addDivider()
            }
        }
    }


    private fun createChatModeItemView(item: ChatMode, position: Int): View {
        val binding = LayoutItemChatModeBinding.inflate(LayoutInflater.from(context), mBinding.itemsContainer, false)
        binding.itemName.text  = item.name
        binding.modeDescription.text  = item.description
        binding.ivSelectedIndi.setImageResource(if (item.isSelected) R.drawable.sound_item_selected else R.drawable.sound_item_unselected)
        binding.ivVipDidi.isVisible = item.onlyVip


        binding.root.setOnClickListener {
            selectItem(position)
            mEventListener?.onItemSelected(position, item)
        }
        return binding.root
    }

    private fun addDivider() {
        val divider = View(context).apply {
            layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, 1.dp).apply {
                setBackgroundColor(context.resources.getColor(R.color.chat_setting_divider_color))
                marginStart = 10.dp
                marginEnd = 10.dp
            }
        }
        mBinding.itemsContainer.addView(divider)
    }


    fun selectItem(position: Int) {
        items.forEachIndexed { index, item ->
            item.isSelected = index == position
        }
        updateItemsView()

        if (position in items.indices) {
            mBinding.titleText.text = items[position].name
        }

        collapse()
    }


    fun toggle() {
        if (isExpanded) collapse() else expand()
        mEventListener?.onExpanded(isExpanded)
    }

    fun expand() {
        if (isExpanded) return

        isExpanded = true
        mBinding.itemsContainer.visibility = VISIBLE
        animateArrow(0f, 90f)
        // param height anim
        val animator = ValueAnimator.ofInt(0, getItemsHeight())
        animator.duration = animationDuration.toLong()
        animator.interpolator = AccelerateDecelerateInterpolator()
        animator.addUpdateListener { animation ->
            val value = animation.animatedValue as Int
            val params = mBinding.itemsContainer.layoutParams
            params.height = value
            mBinding.itemsContainer.layoutParams = params
        }
        animator.start()
    }


    fun collapse() {
        if (!isExpanded) return

        isExpanded = false
        animateArrow(90f, 0f)
        // param height anim
        val animator = ValueAnimator.ofInt(getItemsHeight(), 0)
        animator.duration = animationDuration.toLong()
        animator.interpolator = AccelerateDecelerateInterpolator()
        animator.addUpdateListener { animation ->
            val value = animation.animatedValue as Int
            val params = mBinding.itemsContainer.layoutParams
            params.height = value
            mBinding.itemsContainer.layoutParams = params
        }
        animator.addListener(object : AnimatorListenerAdapter() {
            override fun onAnimationEnd(animation: Animator) {
                mBinding.itemsContainer.visibility = GONE
            }
        })
        animator.start()
    }

    private fun animateArrow(from: Float, to: Float) {
        val rotation = ObjectAnimator.ofFloat(mBinding.arrow, "rotation", from, to)
        rotation.duration = animationDuration.toLong()
        rotation.interpolator = AccelerateDecelerateInterpolator()
        rotation.start()
    }

    private fun getItemsHeight(): Int {
        var height = 0
        for (i in 0 until mBinding.itemsContainer.childCount) {
            val child = mBinding.itemsContainer.getChildAt(i)
            child.measure(
                MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
                MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)
            )
            height += child.measuredHeight
        }
        return height
    }


}