package com.adealink.weparty.commonui.text

import android.text.Selection
import android.text.Spannable
import android.text.SpannableStringBuilder
import android.view.KeyEvent
import android.widget.EditText
import androidx.appcompat.widget.AppCompatEditText
import com.adealink.weparty.commonui.text.span.DataBindingSpan
import com.adealink.weparty.commonui.text.span.IDataBindingSpan
import com.adealink.weparty.commonui.text.span.NoCopySpanEditableFactory
import com.adealink.weparty.commonui.text.watcher.DirtySpanWatcher
import com.adealink.weparty.commonui.text.watcher.SelectionSpanWatcher

object DataBindingSpanHelper {
    fun init(editText: AppCompatEditText) {
        editText.text = null
        editText.setEditableFactory(
            NoCopySpanEditableFactory(
                SelectionSpanWatcher(DataBindingSpan::class),
                DirtySpanWatcher(DataBindingSpan::class) { true }
            )
        )
        editText.setOnKeyListener { v, keyCode, event ->
            if (keyCode == KeyEvent.KEYCODE_DEL && event.action == KeyEvent.ACTION_DOWN) {
                onDelDown((v as EditText).text)
            }
            return@setOnKeyListener false
        }
    }

    private fun onDelDown(text: Spannable): Boolean {
        val selectionStart = Selection.getSelectionStart(text)
        val selectionEnd = Selection.getSelectionEnd(text)
        text.getSpans(selectionStart, selectionEnd, IDataBindingSpan::class.java).firstOrNull { text.getSpanEnd(it) == selectionStart }?.run {
            return (selectionStart == selectionEnd).also {
                val spanStart = text.getSpanStart(this)
                val spanEnd = text.getSpanEnd(this)
                Selection.setSelection(text, spanStart, spanEnd)
            }
        }
        return false
    }

    fun newSpannable(span: DataBindingSpan): Spannable {
        return span.getSpannableString()
    }

    fun applyDataBindingSpans(text: CharSequence, vararg spans: DataBindingSpan): Spannable {
        return SpannableStringBuilder(text).apply {
            spans.forEach {
                if (it.start >= 0 && it.end >= 0 && it.start != it.end) {
                    it.setSpan(this, it.start, it.end)
                }
                //未指定start和end情况，根据placeholder计算占位start和end，并用替换占位内容为replaceContent
                val placeholder = it.placeholder
                if (placeholder.isNullOrEmpty()) {
                    //placeholder为空，直接返回
                    return@forEach
                }
                val placeholderStartIndex = this.indexOf(it.placeholder)
                if (placeholderStartIndex != -1) {
                    val replaceContent = it.replaceContent
                    if (replaceContent.isNullOrEmpty()) {
                        //替换内容为空，直接对placeHolder进行替换
                        it.setSpan(
                            this,
                            placeholderStartIndex,
                            placeholderStartIndex + placeholder.length
                        )
                        return@forEach
                    }
                    this.replace(
                        placeholderStartIndex,
                        placeholderStartIndex + placeholder.length,
                        replaceContent
                    )
                    // 更新 span 的起止位置
                    val start = placeholderStartIndex
                    val end = placeholderStartIndex + replaceContent.length
                    it.setSpan(this, start, end)
                }
            }
        }
    }

    fun getDataBindingSpansSummary(text: CharSequence, vararg spans: DataBindingSpan): Spannable {
        return SpannableStringBuilder(text).apply {
            spans.forEach {
                if (it.start >= 0 && it.end >= 0 && it.start != it.end) {
                    //无占位符，直接返回
                    return@forEach
                }
                //未指定start和end情况，将placeholder替换为空或者用替换占位内容为replaceContent
                val placeholder = it.placeholder
                if (placeholder.isNullOrEmpty()) {
                    //placeholder为空，直接返回
                    return@forEach
                }
                val placeholderStartIndex = this.indexOf(it.placeholder)
                if (placeholderStartIndex != -1) {
                    val replaceContent = it.replaceContent
                    if (replaceContent.isNullOrEmpty()) {
                        //替换内容为空，直接将placeHolder替换为空
                        this.replace(
                            placeholderStartIndex,
                            placeholderStartIndex + placeholder.length,
                            ""
                        )
                        return@forEach
                    }
                    this.replace(
                        placeholderStartIndex,
                        placeholderStartIndex + placeholder.length,
                        replaceContent
                    )
                }
            }
        }
    }
}