package com.develop.common.widget

import android.annotation.SuppressLint
import android.content.Context
import android.graphics.Color
import android.util.AttributeSet
import android.util.Log
import android.view.View
import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.recyclerview.widget.LinearSnapHelper
import com.develop.base.ext.updateText
import com.develop.common.R
import com.develop.common.databinding.TimePickerViewBinding
import com.drake.brv.utils.linear
import com.drake.brv.utils.models
import com.drake.brv.utils.setup


class TimePickerView : ConstraintLayout {

    private var binding: TimePickerViewBinding

    private var timeColor = Color.WHITE
    private val firstData = mutableListOf<String>()
    private val secondData = mutableListOf<String>()

    private var firstTimePos = 0
    private var secondTimePos = 0

    private var maxTime = 8 * 60 * 60
    private var minTime = 0

    var onTimePickerCallback: OnTimePickerCallback? = null
    private var firstManager: ScrollLinearManager
    private var secondManager: ScrollLinearManager

    constructor(context: Context) : super(context) {}
    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
        initAttrs(context, attrs)
    }

    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
        context,
        attrs,
        defStyleAttr
    ) {
        initAttrs(context, attrs)
    }

    init {
        val root = View.inflate(context, R.layout.time_picker_view, this)
        binding = TimePickerViewBinding.bind(root)
        repeat(60) { idx ->
            if (idx < 10) {
                firstData.add("0$idx")
                secondData.add("0$idx")
            } else {
                firstData.add(idx.toString())
                secondData.add(idx.toString())
            }
        }
        repeat(99) { idx ->
            if (idx == 0) {
                return@repeat
            }
            if (idx < 10) {
                firstData.add("0$idx")
            } else {
                firstData.add(idx.toString())
            }
        }
        firstManager = ScrollLinearManager(context)
        secondManager = ScrollLinearManager(context)
    }

    @SuppressLint("ClickableViewAccessibility")
    private fun initAttrs(context: Context, attrs: AttributeSet?) {
        context.obtainStyledAttributes(attrs, R.styleable.TimePickerView).apply {
            timeColor = getColor(R.styleable.TimePickerView_time_color, Color.WHITE)
        }.recycle()
        binding.tvDotTime.setTextColor(timeColor)
        binding.tvFirstBottom.setTextColor(timeColor)
        binding.tvSecondBottom.setTextColor(timeColor)
        binding.tvSetTimeFirst.apply {
            layoutManager = firstManager
            setup {
                addType<String>(R.layout.item_cook_time)
                onBind {
                    val tvTime = findView<TextView>(R.id.tv_time)
                    tvTime.updateText(getModel())
                    tvTime.setTextColor(timeColor)
                }
            }
        }.models = firstData

        binding.tvSetTimeSecond.apply {
            layoutManager = secondManager
            setup {
                addType<String>(R.layout.item_cook_time)
                onBind {
                    val tvTime = findView<TextView>(R.id.tv_time)
                    tvTime.updateText(getModel())
                    tvTime.setTextColor(timeColor)
                }
            }
        }.models = secondData

        binding.tvSetTimeFirst.addOnScrollListener(LinearPositionObserver { pos ->
            firstTimePos = pos
            checkChangeTimeScale(pos)
            updateDisplayTime()
        })
        binding.tvSetTimeFirst.setOnTouchListener { view, motionEvent ->
            onTimePickerCallback?.onTimePickerTouchFirst()
            false
        }
        binding.tvSetTimeSecond.addOnScrollListener(LinearPositionObserver { pos ->
            secondTimePos = pos
            updateDisplayTime()
        })
        binding.tvSetTimeSecond.setOnTouchListener { view, motionEvent ->
            onTimePickerCallback?.onTimePickerTouchFirst()
            false
        }
        LinearSnapHelper().attachToRecyclerView(binding.tvSetTimeFirst)
        LinearSnapHelper().attachToRecyclerView(binding.tvSetTimeSecond)
    }

    private fun checkChangeTimeScale(firstPos: Int) {
        val firstUnit: String
        val secondUnit: String
        if (firstPos >= 60) {
            firstUnit = "hour"
            secondUnit = "min"
        } else {
            firstUnit = "min"
            secondUnit = "sec"
        }
        if (firstUnit != binding.tvFirstBottom.text) {
            binding.tvFirstBottom.text = firstUnit
        }
        if (secondUnit != binding.tvSecondBottom.text) {
            binding.tvSecondBottom.text = secondUnit
        }
    }

    private fun updateDisplayTime() {
        checkLimitTime(true)
        if (firstTimePos >= 60) {
            setTimeInternal(
                firstTimePos - 60 + 1,
                secondTimePos,
                0,
                true,
                setByUser = true
            )
        } else {
            setTimeInternal(
                0,
                firstTimePos,
                secondTimePos,
                true,
                setByUser = true
            )
        }
    }

    @SuppressLint("SetTextI18n")
    fun setTimeInternal(
        hours: Int,
        minute: Int,
        second: Int,
        changeSetting: Boolean,
        setByUser: Boolean = false
    ) {
        val firstTime: Int
        val secondTime: Int
        if (hours > 0 || minute >= 60) {
            checkChangeTimeScale(80)
            firstTime = (hours + minute / 60)
            secondTime = (minute % 60)
        } else {
            checkChangeTimeScale(30)
            firstTime = minute
            secondTime = second
        }
        binding.let {
            if (changeSetting) {
                firstTimePos = if (hours > 0) {
                    59 + firstTime
                } else {
                    firstTime
                }
                secondTimePos = secondTime
                it.tvSetTimeFirst.scrollToPosition(firstTimePos)
                it.tvSetTimeSecond.scrollToPosition(secondTimePos)
            }
            val firstStr = if (firstTime < 10) {
                "0$firstTime"
            } else {
                firstTime.toString()
            }
            val secondStr = if (secondTime < 10) {
                "0$secondTime"
            } else {
                secondTime.toString()
            }
            onTimePickerCallback?.onTimePicker(
                hours,
                minute,
                second,
                "${firstStr}:${secondStr}",
                setByUser
            )
        }
        Log.d("PickerView", "h:${hours}, m:${minute}, s:${second}, setByUser:${setByUser}")
    }

    /**
     * 设置最大最小时间
     * 单位秒
     */
    fun setTimeRange(minTime: Int, maxTime: Int) {
        this.minTime = minTime
        this.maxTime = maxTime
        checkLimitTime()
    }

    private fun checkLimitTime(setByUser: Boolean = false) {
        val minMinutes = (minTime / 60 % 60)
        val minHours = (minTime / 3600)
        val minSeconds = minTime % 60
        val maxMinutes = (maxTime / 60 % 60)
        val maxHours = (maxTime / 3600)
        val maxSeconds = maxTime % 60
        val currentSeconds: Int = if (firstTimePos >= 60) {
            val hours = firstTimePos - 60 + 1
            hours * 60 * 60 + secondTimePos * 60
        } else {
            firstTimePos * 60 + secondTimePos
        }
        if (currentSeconds < minTime) {
            setTimeInternal(
                minHours,
                minMinutes,
                minSeconds,
                changeSetting = true,
                setByUser = setByUser
            )
        } else if (currentSeconds > maxTime) {
            setTimeInternal(
                maxHours,
                maxMinutes,
                maxSeconds,
                changeSetting = true,
                setByUser = setByUser
            )
        }
    }

    fun setTargetTime(time: String) {
        binding.tvTargetTime.visibility = View.VISIBLE
        binding.tvTargetTime.text = time
    }

    fun hideTargetTime() {
        binding.tvTargetTime.visibility = View.INVISIBLE
    }

    fun isTimeCanChange(isCanChange: Boolean) {
        firstManager.setCanScrollVertically(isCanChange)
        secondManager.setCanScrollVertically(isCanChange)
    }

    interface OnTimePickerCallback {
        fun onTimePicker(hours: Int, minute: Int, second: Int, time: String, setByUser: Boolean)
        fun onTimePickerTouchFirst()
    }
}