package com.gh.gamecenter.common.utils

import android.content.ClipboardManager
import android.content.Context
import android.graphics.Color
import android.text.*
import android.text.style.ClickableSpan
import android.text.style.ForegroundColorSpan
import android.text.style.RelativeSizeSpan
import android.view.View
import android.widget.EditText
import android.widget.TextView
import androidx.annotation.ColorRes
import androidx.core.content.ContextCompat
import com.gh.gamecenter.common.HaloApp
import com.gh.gamecenter.common.R
import com.gh.gamecenter.common.callback.SimpleCallback
import com.gh.gamecenter.common.view.CustomLinkMovementMethod
import com.gh.gamecenter.common.view.RoundStrokeBackgroundColorSpan
import com.gh.gamecenter.core.utils.ClickUtils
import com.gh.gamecenter.core.utils.DisplayUtils
import com.gh.gamecenter.core.utils.ToastUtils
import com.lightgame.utils.Utils
import java.util.*
import java.util.regex.Pattern

object TextHelper {

    @JvmStatic
    fun limitTheLengthOfEditText(
        editText: EditText,
        length: Int,
        exceedCallback: ExceedTextLengthLimitCallback? = null
    ) {
        editText.addTextChangedListener(object : TextWatcher {
            override fun afterTextChanged(s: Editable?) {

            }

            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {

            }

            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
                val tvCount = editText.text.toString().length
                if (tvCount > length) {
                    val str = editText.text.toString().substring(0, length)
                    editText.setText(str)
                    editText.setSelection(str.length)
                    if (!ClickUtils.isFastDoubleClick(editText.id, 2000)) {
                        exceedCallback?.onExceed()
                    }
                }
            }
        })
    }

    @JvmStatic
    fun getFilter(maxLength: Int, msg: String)//限制最大长度-Toast弹窗提示
            : InputFilter {
        return InputFilter { source, start, end, dest, dstart, dend ->
            val keep = maxLength - (dest.length - (dend - dstart))
            if (keep < end - start) {
                ToastUtils.showToast(msg)
            }
            when {
                keep <= 0 -> ""
                keep >= end - start -> null
                else -> source.subSequence(start, start + keep)
            }
        }
    }

    //限制最大长度(1个emoji表情算作1个字符)-Toast弹窗提示
    @JvmStatic
    fun getFilterOfEmojiHalf(maxLength: Int, msg: String)
            : InputFilter {
        return InputFilter { source, start, end, dest, dstart, dend ->
            val newMaxLength = maxLength + source.toString().emojiCount() + dest.toString().emojiCount()
            val keep = newMaxLength - (dest.length - (dend - dstart))
            if (keep < end - start) {
                ToastUtils.showToast(msg)
            }
            when {
                keep <= 0 -> ""
                keep >= end - start -> null
                else -> source.subSequence(start, start + keep - source.toString().emojiCount())
            }
        }
    }

    //限制最大长度(空格不算入字数判断)-Toast弹窗提示
    @JvmStatic
    fun getFilterIgnoreBlank(maxLength: Int, msg: String): InputFilter {
        return InputFilter { source, start, end, dest, dstart, dend ->
            val newMaxLength = maxLength + getBlankCount(source.toString()) + getBlankCount(dest.toString())
            val keep = newMaxLength - (dest.length - (dend - dstart))
            if (keep < end - start) {
                ToastUtils.showToast(msg)
            }
            when {
                keep <= 0 -> ""
                keep >= end - start -> null
                else -> source.subSequence(start, start + keep)
            }
        }
    }

    private fun getBlankCount(text: String): Int {
        var blankCount = 0
        val toCharArray = text.toCharArray()
        toCharArray.forEach {
            if (it == ' ') {
                blankCount++
            }
        }
        return blankCount
    }

    @JvmStatic
    fun highlightTextThatIsWrappedInsideWrapperByDefault(textView: TextView, text: String?) {
        textView.text = getHighlightedSpannableStringThatIsWrappedInsideWrapper(textView.context, text
            ?: "", "###", R.color.theme_font, object : SimpleCallback<String> {
            override fun onCallback(arg: String) {
                val application = HaloApp.getInstance()
                val cmb = application.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
                cmb.text = arg
                Utils.toast(application, "已复制：$arg")
            }
        })
        textView.movementMethod = CustomLinkMovementMethod.getInstance()
        textView.highlightColor = Color.TRANSPARENT
    }

    @JvmStatic
    fun highlightTextThatIsWrappedInsideWrapper(
        textView: TextView,
        text: CharSequence,
        wrapper: String,
        @ColorRes
        highlightColorId: Int,
        highlightedTextClickListener: SimpleCallback<String>? = null
    ) {
        textView.text =
            getHighlightedSpannableStringThatIsWrappedInsideWrapper(
                textView.context,
                text,
                wrapper,
                highlightColorId,
                highlightedTextClickListener
            )
        textView.movementMethod = CustomLinkMovementMethod.getInstance()
        textView.highlightColor = Color.TRANSPARENT
    }

    @JvmStatic
    fun getHighlightedSpannableStringThatIsWrappedInsideWrapper(
        context: Context,
        text: CharSequence,
        wrapper: String = "###",
        @ColorRes
        highlightColorId: Int = R.color.theme_font,
        highlightedTextClickListener: SimpleCallback<String>? = object : SimpleCallback<String> {
            override fun onCallback(arg: String) {
                val application = HaloApp.getInstance()
                val cmb = application.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
                cmb.text = arg
                Utils.toast(application, "已复制：$arg")
            }
        }
    ): SpannableStringBuilder {
        val builder = SpannableStringBuilder(text)
        return updateSpannableStringWithHighlightedSpan(
            context,
            builder,
            wrapper,
            highlightColorId,
            highlightedTextClickListener
        )
    }

    fun updateSpannableStringWithHighlightedSpan(
        context: Context,
        ssb: SpannableStringBuilder,
        wrapper: String = "###",
        @ColorRes
        highlightColorId: Int = R.color.theme_font,
        highlightedTextClickListener: SimpleCallback<String>? = object : SimpleCallback<String> {
            override fun onCallback(arg: String) {
                val application = HaloApp.getInstance()
                val cmb = application.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
                cmb.text = arg
                Utils.toast(application, "已复制：$arg")
            }
        }
    ): SpannableStringBuilder {

        if (ssb.endsWith(wrapper)) {
            // 若高亮符在最后一位就在后面加一个空格，避免整行都能点击
            ssb.append(" ")
        }

        val wrapperTextLength = wrapper.length
        val matcher = Pattern.compile("$wrapper(.+?)$wrapper", Pattern.DOTALL).matcher(ssb)

        val pair = TreeMap<Int, Int>()
        while (matcher.find()) {
            // 保存起始位置和结束位置
            pair[matcher.start(1)] = matcher.end(1)
            ssb.setSpan(object : ClickableSpan() {
                override fun updateDrawState(ds: TextPaint) {
                    super.updateDrawState(ds)
                    ds.color = ContextCompat.getColor(context, highlightColorId)
                    ds.isUnderlineText = false
                }

                override fun onClick(widget: View) {
                    val tv = widget as TextView
                    val s = tv.text as Spanned
                    val start = s.getSpanStart(this)
                    val end = s.getSpanEnd(this)
                    highlightedTextClickListener?.onCallback(s.substring(start, end))
                }
            }, matcher.start(1), matcher.end(1), 0)
        }

        // 反转 pair
        val reversePair = pair.descendingMap()

        // 找到
        for (key in reversePair.keys) {
            val end = reversePair[key]

            end?.let {
                ssb.replace(end, end + wrapperTextLength, "")
                ssb.replace(key - wrapperTextLength, key, "")
            }
        }

        return ssb
    }

    /**
     * [amwayStyle] 是否为安利墙列表样式，安利墙列表样式与其它地方略有不同
     */
    fun getCommentLabelSpannableStringBuilder(
        comment: CharSequence,
        amwayStyle: Boolean = false,
        tagStrokeColor: String = "#FA8E00",
        tagTextColor: String = "#FA8E00"
    ): SpannableStringBuilder {
        val contents = SpannableStringBuilder()
        var count = 0
        val splits = comment.split("<tag>")
        splits.forEachIndexed { index, s ->
            if (index != 0) {
                val item = "<tag>$s"
                val pattern = Pattern.compile("<tag>(\\S+)</tag>([\\S\\s\n]+)")
                val matcher = pattern.matcher(item)
                if (matcher.find()) {
                    val label = matcher.group(1)
//                    val content = matcher.group(2) //不知为什么这里正则不能匹配颜文字，所以就用字符串裁剪。。。
                    var content = item.substring(item.indexOf("</tag>") + 6)
                    if (index == splits.size - 1) content += " "
                    val newLabel = "  $label   "
                    contents.append(newLabel)
                    contents.setSpan(
                        RelativeSizeSpan(0.8f),
                        count,
                        count + newLabel.length - 1,
                        Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
                    )
                    contents.setSpan(
                        getRoundStrokeBackgroundColorSpan(amwayStyle, tagStrokeColor, tagTextColor),
                        count,
                        count + newLabel.length - 1,
                        Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
                    )
                    count += newLabel.length
                    contents.append(content)
                    count += content.length
                }
            } else {
                contents.append(s)
                count += s.length
            }
        }
        return contents
    }

    @JvmStatic
    fun getCommentLabelSpannableStringBuilder(comment: CharSequence, colorRes: Int): SpannableStringBuilder {
        val contents = SpannableStringBuilder()
        var count = 0
        val splits = comment.split("<tag>")
        splits.forEachIndexed { index, s ->
            if (index != 0) {
                val item = "<tag>$s"
                val pattern = Pattern.compile("<tag>(\\S+)</tag>([\\S\\s\n]+)")
                val matcher = pattern.matcher(item)
                if (matcher.find()) {
                    val label = matcher.group(1)
                    var content = item.substring(item.indexOf("</tag>") + 6)
                    if (index == splits.size - 1) content += " "
                    val newLabel = "#$label#  "
                    contents.append(newLabel)
                    contents.setSpan(
                        ForegroundColorSpan(ContextCompat.getColor(HaloApp.getInstance(), colorRes)),
                        count, count + newLabel.length - 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
                    )
                    count += newLabel.length
                    contents.append(content)
                    count += content.length
                }
            } else {
                contents.append(s)
                count += s.length
            }
        }
        return contents
    }

    private fun getRoundStrokeBackgroundColorSpan(
        amwayStyle: Boolean,
        tagStrokeColor: String,
        tagTextColor: String
    ): RoundStrokeBackgroundColorSpan {
        return if (amwayStyle) {
            val strokeWidth = DisplayUtils.dip2px(1F)

            RoundStrokeBackgroundColorSpan(
                tagStrokeColor.hexStringToIntColor(),
                tagTextColor.hexStringToIntColor(),
                strokeWidth,
                DisplayUtils.sp2px(HaloApp.getInstance(), 10F)
            )
        } else {
            RoundStrokeBackgroundColorSpan(
                tagStrokeColor.hexStringToIntColor(),
                tagTextColor.hexStringToIntColor()
            )
        }
    }

    fun interface ExceedTextLengthLimitCallback {
        fun onExceed()
    }

}