package com.adealink.weparty.commonui.widget.operatebox

import android.content.Context
import android.util.AttributeSet
import android.util.SparseIntArray
import android.view.View
import android.widget.LinearLayout
import androidx.annotation.IdRes
import androidx.annotation.Px
import androidx.core.util.isEmpty
import com.adealink.weparty.BuildConfig
import com.adealink.weparty.R

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

    private var layersDefine: IntArray = intArrayOf()
    private val layerViewIndexSA = SparseIntArray()

    private var listener: OperateBoxListener? = null


    @Px
    private var iconSizePx = 0

    @Px
    private var itemWidthPx = 0

    @Px
    private var itemHeightPx = 0

    init {
        var obOrientation = HORIZONTAL
        attrs?.apply {
            val a = context.obtainStyledAttributes(this, R.styleable.OperateBox)
            iconSizePx = a.getDimensionPixelSize(R.styleable.OperateBox_icon_size, iconSizePx)
            itemWidthPx = a.getDimensionPixelSize(R.styleable.OperateBox_item_width, itemWidthPx)
            itemHeightPx = a.getDimensionPixelSize(R.styleable.OperateBox_item_height, itemHeightPx)
            obOrientation = a.getInt(R.styleable.OperateBox_orientation, HORIZONTAL)
            a.recycle()
        }
        orientation = obOrientation
    }

    fun setLayersDefine(layersDefine: IntArray) {
        this.layersDefine = layersDefine
    }

    fun setListener(listener: OperateBoxListener?) {
        this.listener = listener
    }

    /**
     * 添加操作项
     * @param item: 操作项
     */
    fun <V1 : View, V2 : View> addItem(item: OperateBoxItem<V1, V2>) {
        val itemView = findViewById<View>(item.id)
        if (itemView != null) {
            removeView(itemView)
        }
        addItem(item, getViewIndex(item.id))
    }

    private fun <V1 : View, V2 : View> addItem(item: OperateBoxItem<V1, V2>, index: Int = -1) {
        val itemView = OperateBoxItemView<V1, V2>(context).apply {
            id = item.id
            setItem(item, iconSizePx, iconSizePx)
        }
        itemView.setOnClickListener { listener?.onOperateItemClick(item) }
        addView(itemView, index, LayoutParams(itemWidthPx, itemHeightPx))
    }

    private fun getViewIndex(id: Int): Int {
        val defineIndex = getLayerViewIndex(id)
        if (defineIndex == -1) {
            if (BuildConfig.DEBUG) {
                throw IllegalStateException("Item(${resources.getResourceName(id)}) 层级未定义")
            }
            return defineIndex
        }

        //往靠近自己的两头开始找
        var targetView: View? = null
        var targetIndex = -1
        var up = 1
        var down = 1
        var upBaseIndex = -1
        var downBaseIndex = -1
        while (!(defineIndex - up < 0 && defineIndex + down >= layersDefine.size)) {
            if (defineIndex - up >= 0) {
                targetView = findViewById(layersDefine[defineIndex - up])
                if (targetView != null) {
                    targetIndex = indexOfChild(targetView)
                    upBaseIndex = targetIndex
                    break
                }
                up++
            }
            if (defineIndex + down < layersDefine.size) {
                targetView = findViewById(layersDefine[defineIndex + down])
                if (targetView != null) {
                    targetIndex = indexOfChild(targetView)
                    downBaseIndex = targetIndex
                    break
                }
                down++
            }
        }

        return when {
            upBaseIndex != -1 -> {
                upBaseIndex + 1
            }

            downBaseIndex != -1 -> {
                downBaseIndex
            }

            else -> {
                -1
            }
        }
    }

    /**
     * 获取视图定义层级(通过映射提升检索效率)
     */
    private fun getLayerViewIndex(@IdRes id: Int): Int {
        if (layerViewIndexSA.isEmpty()) {
            layersDefine.forEachIndexed { index, value ->
                layerViewIndexSA.put(value, index)
            }
        }

        return layerViewIndexSA.get(id, -1)
    }

    /**
     * 移除操作项
     */
    fun removeItem(item: OperateBoxItem<*, *>) {
        removeItem(item.id)
    }

    fun removeItem(id: Int) {
        val itemView = findViewById<View>(id) ?: return
        removeView(itemView)
    }

    fun removeAllItems() {
        removeAllViews()
    }

    fun <V1 : View, V2 : View> findItem(item: OperateBoxItem<V1, V2>): OperateBoxItemView<V1, V2>? {
        val itemView = findViewById<View>(item.id)
        return itemView as? OperateBoxItemView<V1, V2>
    }

    fun findItem(id: Int): OperateBoxItemView<*, *>? {
        val itemView = findViewById<View>(id)
        return itemView as? OperateBoxItemView<*, *>
    }

    interface OperateBoxListener {
        fun onOperateItemClick(item: OperateBoxItem<*, *>)
    }

}