package com.cheng.blzb.widget

import android.animation.ValueAnimator
import android.content.Context
import android.util.AttributeSet
import android.view.View
import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.animation.addListener
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.chad.library.adapter.base.BaseQuickAdapter
import com.chad.library.adapter.base.viewholder.BaseViewHolder
import com.cheng.blzb.R
import com.example.base.extensions.visible
import com.example.base.utils.DensityUtils
import java.text.DecimalFormat
import kotlin.math.roundToInt

class BarChartView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : FrameLayout(context, attrs, defStyleAttr) {
    private val xAxisAdapter by lazy { XAxisAdapter() }

    private val yAxisAdapter by lazy { YAxisAdapter() }
    private val xAxisColumnCount = 6

    private val yAxisRowCount = 6

    private var maxYAxisValue = 0f

    init {
        initXAxisData()
        initYAxisData()
    }

    /**
     * 初始化X轴
     */
    private fun initXAxisData() {
        val rvXAxis = RecyclerView(context)
        rvXAxis.adapter = xAxisAdapter
        rvXAxis.layoutManager = LinearLayoutManager(context, RecyclerView.HORIZONTAL, false)
        val xAxisLp = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
        xAxisLp.marginStart = DensityUtils.dp2px(40f)
        rvXAxis.layoutParams = xAxisLp
        addView(rvXAxis)
    }

    /**
     * 初始化Y轴
     */
    private fun initYAxisData() {
        val rvYAxis = RecyclerView(context)
        rvYAxis.adapter = yAxisAdapter
        rvYAxis.layoutManager = LinearLayoutManager(context, RecyclerView.VERTICAL, false)
        val yAxisLp = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
        yAxisLp.bottomMargin = DensityUtils.dp2px(15f)
        rvYAxis.layoutParams = yAxisLp
        rvYAxis.overScrollMode = OVER_SCROLL_NEVER
        addView(rvYAxis, 0)
    }

    /**
     * 设置数据
     */
    fun setData(data: List<BarDataSet>) {
        val allValues = mutableListOf<Float>()
        data.forEach { allValues.addAll(it.values) }

        val yValueList = mutableListOf<YAxisValue>()
        val rowValue = allValues.maxBy { it } / yAxisRowCount
        val value = if (rowValue > 10) {
            var bigNum = rowValue.toInt().toFloat()
            val numLength = rowValue.toInt().toString().length
            for (i in 0 until numLength - 1) {
                bigNum /= 10
            }
            bigNum = (bigNum + 0.5f).roundToInt().toFloat()
            for (i in 0 until numLength - 1) {
                bigNum *= 10
            }
            bigNum
        } else rowValue

        for (i in 0 .. yAxisRowCount) {
            yValueList.add(0, YAxisValue(i * value))
        }
        maxYAxisValue = value * yAxisRowCount

        xAxisAdapter.setList(data.map { XAxisValue(it.key, it.values) })
        yAxisAdapter.setList(yValueList)
    }

    data class BarDataSet(val key: String, val values: List<Float>)

    data class XAxisValue(val key: String, val values: List<Float>, var anim: Boolean = true)

    data class YAxisValue(val value: Float)

    inner class XAxisAdapter() : BaseQuickAdapter<XAxisValue, BaseViewHolder>(R.layout.listitem_bar_chart_x) {
        override fun convert(holder: BaseViewHolder, item: XAxisValue) {
            val lp = holder.itemView.layoutParams as RecyclerView.LayoutParams
            lp.width = recyclerView.measuredWidth / xAxisColumnCount
            holder.itemView.layoutParams = lp

            holder.setText(R.id.tv_key, item.key)

            val container = holder.getView<FrameLayout>(R.id.layout_container)
            container.removeAllViews()

            item.values.forEachIndexed { index, value ->
                val view = inflate(context, R.layout.layout_x_axis_bar, null)
                val tvValue = view.findViewById<TextView>(R.id.tv_value)
                val ivBar = view.findViewById<ImageView>(R.id.iv_bar)
                val ivBarTop = view.findViewById<ImageView>(R.id.iv_bar_top)

                tvValue.text = DecimalFormat("0.#").format(value)
                if (index == 0) {
                    ivBar.setImageResource(R.mipmap.ic_bar_chart1)
                    ivBarTop.setImageResource(R.mipmap.ic_bar_chart_top1)
                } else {
                    ivBar.setImageResource(R.mipmap.ic_bar_chart2)
                    ivBarTop.setImageResource(R.mipmap.ic_bar_chart_top2)
                }
                container.addView(view)

                val barHeight = (value / maxYAxisValue * recyclerView.measuredHeight * yAxisRowCount / (yAxisRowCount + 1)).toInt() - DensityUtils.dp2px(10f)
                if (item.anim) {
                    startAnimation(ivBar, barHeight)
                    item.anim = false
                } else {
                    val lp = ivBar.layoutParams as ConstraintLayout.LayoutParams
                    lp.height = barHeight.coerceAtLeast(DensityUtils.dp2px(7f))
                    ivBar.layoutParams = lp
                    ivBar.visible()
                }
            }
        }

        private fun startAnimation(barView: View, height: Int) {
            val valueAnim = ValueAnimator.ofFloat(0f, 1f)
            valueAnim.addUpdateListener { animator ->
                val lp = barView.layoutParams as ConstraintLayout.LayoutParams
                val value = animator.animatedValue as Float
                lp.height = (value * height).coerceAtLeast(DensityUtils.dp2px(6f).toFloat()).toInt()
                barView.layoutParams = lp
            }
            valueAnim.addListener(onStart = {
                barView.visible()
            })
            valueAnim.duration = 2000
            valueAnim.start()
        }
    }

    inner class YAxisAdapter() : BaseQuickAdapter<YAxisValue, BaseViewHolder>(R.layout.listitem_bar_chart_y) {

        override fun convert(holder: BaseViewHolder, item: YAxisValue) {
            val lp = holder.itemView.layoutParams as RecyclerView.LayoutParams
            lp.height = recyclerView.measuredHeight / (yAxisRowCount + 1)
            holder.itemView.layoutParams = lp

            holder.setText(R.id.tv_value, DecimalFormat("0.#").format(item.value))
        }
    }
}