package com.adealink.weparty.commonui.text.watcher

import android.text.Selection
import android.text.Spannable
import kotlin.math.abs
import kotlin.reflect.KClass

class SelectionSpanWatcher<T : Any>(private val kClass: KClass<T>) : SpanWatcherAdapter() {
    private var selStart = 0
    private var selEnd = 0
    override fun onSpanChanged(text: Spannable, what: Any, ostart: Int, oend: Int, nstart: Int, nend: Int) {
        if (what === Selection.SELECTION_END && selEnd != nstart) {
            selEnd = nstart
            text.getSpans(nstart, nend, kClass.java).firstOrNull()?.run {
                val spanStart = text.getSpanStart(this)
                val spanEnd = text.getSpanEnd(this)
                val index = if (abs(selEnd - spanEnd) > abs(selEnd - spanStart)) spanStart else spanEnd
                val start = Selection.getSelectionStart(text).coerceAtLeast(index)
                if (checkRange(start, index, text.length)) {
                    Selection.setSelection(text, start, index)
                }
            }
        }

        if (what === Selection.SELECTION_START && selStart != nstart) {
            selStart = nstart
            text.getSpans(nstart, nend, kClass.java).firstOrNull()?.run {
                val spanStart = text.getSpanStart(this)
                val spanEnd = text.getSpanEnd(this)
                val index = if (abs(selStart - spanEnd) > abs(selStart - spanStart)) spanStart else spanEnd
                val end = Selection.getSelectionEnd(text).coerceAtMost(index)
                if (checkRange(index, end, text.length)) {
                    Selection.setSelection(text, index, end)
                }
            }
        }
    }

    private fun checkRange(start: Int, end: Int, length: Int): Boolean {
        if (end < start) {
            return false
        }
        if (start > length || end > length) {
            return false
        }
        if (start < 0 || end < 0) {
            return false
        }
        return true
    }

}