package com.rosetta.messenger.ui.components

import android.content.Context
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Paint
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
import android.net.Uri
import android.text.Editable
import android.text.SpannableStringBuilder
import android.text.TextPaint
import android.text.TextWatcher
import android.text.method.LinkMovementMethod
import android.text.style.ClickableSpan
import android.text.style.DynamicDrawableSpan
import android.text.style.ForegroundColorSpan
import android.text.style.ImageSpan
import android.util.AttributeSet
import android.util.LruCache
import android.util.Patterns
import android.view.GestureDetector
import android.view.Gravity
import android.view.MotionEvent
import android.view.View
import android.view.inputmethod.EditorInfo
import android.widget.EditText
import android.widget.FrameLayout
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb
import androidx.compose.foundation.background
import androidx.compose.ui.viewinterop.AndroidView
import java.util.regex.Pattern

private class TelegramLikeEmojiSpan(
    emojiDrawable: Drawable,
    private var sourceFontMetrics: Paint.FontMetricsInt?
) : ImageSpan(emojiDrawable, DynamicDrawableSpan.ALIGN_BOTTOM) {

    private var sizePx: Int = resolveSize(sourceFontMetrics)

    private fun resolveSize(metrics: Paint.FontMetricsInt?): Int {
        val metricsSize = metrics?.let { kotlin.math.abs(it.descent) + kotlin.math.abs(it.ascent) } ?: 0
        if (metricsSize > 0) return metricsSize
        val intrinsic = drawable.intrinsicHeight
        return if (intrinsic > 0) intrinsic else 20
    }

    override fun getSize(
        paint: Paint,
        text: CharSequence,
        start: Int,
        end: Int,
        fm: Paint.FontMetricsInt?
    ): Int {
        val metrics = sourceFontMetrics ?: paint.fontMetricsInt
        sourceFontMetrics = metrics
        sizePx = resolveSize(metrics)
        val scaledSize = sizePx.coerceAtLeast(1)
        drawable.setBounds(0, 0, scaledSize, scaledSize)
        fm?.let {
            it.ascent = metrics.ascent
            it.descent = metrics.descent
            it.top = metrics.top
            it.bottom = metrics.bottom
            it.leading = metrics.leading
        }
        return scaledSize
    }
}

/**
 * Apple Emoji EditText - кастомный EditText с PNG эмодзи
 * Заменяет системные эмодзи на Apple PNG изображения из assets
 */
class AppleEmojiEditTextView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = android.R.attr.editTextStyle
) : EditText(context, attrs, defStyleAttr) {

    var onTextChange: ((String) -> Unit)? = null
    /** Called when the view's measured height changes (for multiline expansion animation). */
    var onHeightChanged: ((oldHeight: Int, newHeight: Int) -> Unit)? = null
    private var isUpdating = false
    private var lastMeasuredHeight: Int = 0

    companion object {
        // Regex для эмодзи - public для доступа из других компонентов
        val EMOJI_PATTERN = Pattern.compile(
            "[\\x{1F600}-\\x{1F64F}]|" +  // Emoticons
            "[\\x{1F300}-\\x{1F5FF}]|" +  // Misc Symbols and Pictographs
            "[\\x{1F680}-\\x{1F6FF}]|" +  // Transport and Map
            "[\\x{1F1E0}-\\x{1F1FF}]|" +  // Flags
            "[\\x{2600}-\\x{26FF}]|" +    // Misc symbols
            "[\\x{2700}-\\x{27BF}]|" +    // Dingbats
            "[\\x{FE00}-\\x{FE0F}]|" +    // Variation Selectors
            "[\\x{1F900}-\\x{1F9FF}]|" +  // Supplemental Symbols
            "[\\x{1FA00}-\\x{1FA6F}]|" +  // Chess Symbols
            "[\\x{1FA70}-\\x{1FAFF}]|" +  // Symbols Extended-A
            "[\\x{231A}-\\x{231B}]|" +    // Watch, Hourglass
            "[\\x{23E9}-\\x{23F3}]|" +    // Media controls
            "[\\x{23F8}-\\x{23FA}]|" +    // Media controls
            "[\\x{25AA}-\\x{25AB}]|" +    // Squares
            "[\\x{25B6}]|[\\x{25C0}]|" +  // Play buttons
            "[\\x{25FB}-\\x{25FE}]|" +    // Squares
            "[\\x{2614}-\\x{2615}]|" +    // Umbrella, Hot beverage
            "[\\x{2648}-\\x{2653}]|" +    // Zodiac
            "[\\x{267F}]|[\\x{2693}]|" +  // Wheelchair, Anchor
            "[\\x{26A1}]|[\\x{26AA}-\\x{26AB}]|" +
            "[\\x{26BD}-\\x{26BE}]|" +    // Sports
            "[\\x{26C4}-\\x{26C5}]|" +    // Weather
            "[\\x{26CE}]|[\\x{26D4}]|" +
            "[\\x{26EA}]|[\\x{26F2}-\\x{26F3}]|" +
            "[\\x{26F5}]|[\\x{26FA}]|[\\x{26FD}]|" +
            "[\\x{2702}]|[\\x{2705}]|" +
            "[\\x{2708}-\\x{270D}]|[\\x{270F}]|" +
            "[\\x{2712}]|[\\x{2714}]|[\\x{2716}]|" +
            "[\\x{271D}]|[\\x{2721}]|" +
            "[\\x{2728}]|[\\x{2733}-\\x{2734}]|" +
            "[\\x{2744}]|[\\x{2747}]|" +
            "[\\x{274C}]|[\\x{274E}]|" +
            "[\\x{2753}-\\x{2755}]|[\\x{2757}]|" +
            "[\\x{2763}-\\x{2764}]|" +
            "[\\x{2795}-\\x{2797}]|[\\x{27A1}]|" +
            "[\\x{27B0}]|[\\x{27BF}]|" +
            "[\\x{2934}-\\x{2935}]|" +
            "[\\x{2B05}-\\x{2B07}]|" +
            "[\\x{2B1B}-\\x{2B1C}]|" +
            "[\\x{2B50}]|[\\x{2B55}]|" +
            "[\\x{3030}]|[\\x{303D}]|" +
            "[\\x{3297}]|[\\x{3299}]"
        )
        
        // 🔥 Паттерн для :emoji_XXXX: формата (как в десктопе)
        val EMOJI_CODE_PATTERN: Pattern = Pattern.compile(":emoji_([a-fA-F0-9_-]+):")

        // Кэш bitmap
        private val bitmapCache = LruCache<String, Bitmap>(500)
    }

    init {
        // Настраиваем EditText
        background = null
        setBackgroundColor(android.graphics.Color.TRANSPARENT)
        setPadding(0, 0, 0, 0)
        gravity = Gravity.CENTER_VERTICAL or Gravity.START
        isSingleLine = false
        maxLines = 5
        imeOptions = EditorInfo.IME_FLAG_NO_EXTRACT_UI
        
        addTextChangedListener(object : TextWatcher {
            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
            override fun afterTextChanged(s: Editable?) {
                if (!isUpdating && s != null) {
                    replaceEmojisWithImages(s)
                    // Отправляем plain text без spans
                    onTextChange?.invoke(s.toString())
                }
            }
        })
    }

    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        if (oldh != 0 && h != oldh) {
            onHeightChanged?.invoke(oldh, h)
        }
        lastMeasuredHeight = h
    }

    fun setTextWithEmojis(newText: String) {
        if (newText == text.toString()) return
        isUpdating = true
        try {
            val cursorPos = selectionStart
            setText(newText)
            // Восстанавливаем позицию курсора в конец текста
            val newCursorPos = if (cursorPos >= 0) newText.length else cursorPos
            setSelection(newCursorPos.coerceIn(0, newText.length))
        } finally {
            isUpdating = false
        }
        replaceEmojisWithImages(editableText)
    }

    private fun replaceEmojisWithImages(editable: Editable) {
        if (isUpdating) return
        isUpdating = true

        try {
            val textStr = editable.toString()
            val cursorPosition = selectionStart
            
            // 🔥 Собираем все позиции эмодзи (и Unicode, и :emoji_code:)
            data class EmojiMatch(val start: Int, val end: Int, val unified: String, val isCodeFormat: Boolean)
            val emojiMatches = mutableListOf<EmojiMatch>()
            
            // 1. Ищем :emoji_XXXX: формат
            val codeMatcher = EMOJI_CODE_PATTERN.matcher(textStr)
            while (codeMatcher.find()) {
                val unified = codeMatcher.group(1) ?: continue
                emojiMatches.add(EmojiMatch(codeMatcher.start(), codeMatcher.end(), unified, true))
            }
            
            // 2. Ищем реальные Unicode эмодзи
            val matcher = EMOJI_PATTERN.matcher(textStr)
            while (matcher.find()) {
                val emoji = matcher.group()
                val start = matcher.start()
                val end = matcher.end()
                
                // Проверяем что этот диапазон не перекрывается с :emoji_XXXX:
                val overlaps = emojiMatches.any { 
                    (start >= it.start && start < it.end) ||
                    (end > it.start && end <= it.end)
                }
                if (!overlaps) {
                    emojiMatches.add(EmojiMatch(start, end, emojiToUnified(emoji), false))
                }
            }
            
            // 3. Обрабатываем все найденные эмодзи
            for (match in emojiMatches) {
                val start = match.start
                val end = match.end

                // Проверяем, есть ли уже ImageSpan
                val existingSpans = editable.getSpans(start, end, ImageSpan::class.java)
                if (existingSpans.isNotEmpty()) continue

                val unified = match.unified
                var bitmap = bitmapCache.get(unified)
                if (bitmap == null) {
                    bitmap = loadFromAssets(unified)
                    if (bitmap != null) {
                        bitmapCache.put(unified, bitmap)
                    }
                }

                if (bitmap != null && start < editable.length && end <= editable.length) {
                    val drawable = BitmapDrawable(resources, bitmap)
                    val imageSpan = TelegramLikeEmojiSpan(drawable, paint.fontMetricsInt)
                    editable.setSpan(imageSpan, start, end, SpannableStringBuilder.SPAN_EXCLUSIVE_EXCLUSIVE)
                }
            }

            // Восстанавливаем курсор, убедившись что он в допустимых пределах
            // 🔥 Захватываем длину ДО post, т.к. text может измениться
            val safePosition = cursorPosition.coerceIn(0, editable.length)
            if (safePosition >= 0) {
                post { 
                    try {
                        val currentLength = text?.length ?: 0
                        if (safePosition <= currentLength) {
                            setSelection(safePosition.coerceIn(0, currentLength))
                        }
                    } catch (e: Exception) {
                        // Игнорируем - текст мог измениться
                    }
                }
            }
        } finally {
            isUpdating = false
        }
    }

    private fun loadFromAssets(unified: String): Bitmap? {
        return try {
            val inputStream = getContext().assets.open("emoji/$unified.png")
            val bitmap = BitmapFactory.decodeStream(inputStream)
            inputStream.close()
            bitmap
        } catch (e: Exception) {
            null
        }
    }

    private fun emojiToUnified(emoji: String): String {
        val codePoints = emoji.codePoints().toArray()
        if (codePoints.isEmpty()) return ""

        val unifiedParts = ArrayList<String>(codePoints.size)
        for (codePoint in codePoints) {
            if (codePoint != 0xFE0F) {
                unifiedParts.add(String.format("%04x", codePoint))
            }
        }

        return unifiedParts.joinToString("-")
    }
}

/**
 * Compose обёртка для AppleEmojiEditText
 */
@Composable
fun AppleEmojiTextField(
    value: String,
    onValueChange: (String) -> Unit,
    modifier: Modifier = Modifier,
    textColor: androidx.compose.ui.graphics.Color = androidx.compose.ui.graphics.Color.White,
    textSize: Float = 16f,
    hint: String = "Message",
    hintColor: androidx.compose.ui.graphics.Color = androidx.compose.ui.graphics.Color.Gray,
    onViewCreated: ((AppleEmojiEditTextView) -> Unit)? = null,
    requestFocus: Boolean = false,
    onFocusChanged: ((Boolean) -> Unit)? = null,
    onHeightChanged: ((oldHeight: Int, newHeight: Int) -> Unit)? = null
) {
    // Храним ссылку на view для управления фокусом
    var editTextView by remember { mutableStateOf<AppleEmojiEditTextView?>(null) }
    
    // 🔥 Автоматический запрос фокуса когда requestFocus = true
    LaunchedEffect(requestFocus) {
        if (requestFocus && editTextView != null) {
            editTextView?.requestFocus()
            // Показываем клавиатуру
            val imm = editTextView?.context?.getSystemService(android.content.Context.INPUT_METHOD_SERVICE) as? android.view.inputmethod.InputMethodManager
            imm?.showSoftInput(editTextView, android.view.inputmethod.InputMethodManager.SHOW_IMPLICIT)
        }
    }
    
    AndroidView(
        factory = { ctx ->
            AppleEmojiEditTextView(ctx).apply {
                setTextColor(textColor.toArgb())
                setHintTextColor(hintColor.toArgb())
                setHint(hint)
                setTextSize(textSize)
                onTextChange = onValueChange
                this.onHeightChanged = onHeightChanged
                // Убираем все возможные фоны у EditText
                background = null
                setBackgroundColor(android.graphics.Color.TRANSPARENT)
                // Сохраняем ссылку на view
                editTextView = this
                // Подключаем callback для изменения фокуса
                setOnFocusChangeListener { _, hasFocus ->
                    onFocusChanged?.invoke(hasFocus)
                }
                // Уведомляем о создании view
                onViewCreated?.invoke(this)
            }
        },
        update = { view ->
            // Always update the callback to prevent stale lambda references
            // after recomposition (e.g., after sending a photo)
            view.onTextChange = onValueChange

            if (view.text.toString() != value) {
                view.setTextWithEmojis(value)
            }
            // Гарантируем прозрачность у EditText
            view.background = null
            // 🔥 Убираем фон у AndroidViewHolder (parent FrameLayout)
            (view.parent as? FrameLayout)?.apply {
                setBackgroundColor(android.graphics.Color.TRANSPARENT)
                background = null
            }
        },
        // 🔥 Прозрачный фон для Compose контейнера
        modifier = modifier.background(Color.Transparent)
    )
}

/**
 * TextView с Apple эмодзи (для отображения, не редактирования)
 * 🔥 Поддержка кликабельных ссылок (URL, email, телефоны)
 */
@Composable
fun AppleEmojiText(
    text: String,
    modifier: Modifier = Modifier,
    color: androidx.compose.ui.graphics.Color = androidx.compose.ui.graphics.Color.White,
    fontSize: androidx.compose.ui.unit.TextUnit = androidx.compose.ui.unit.TextUnit.Unspecified,
    fontWeight: androidx.compose.ui.text.font.FontWeight? = null,
    maxLines: Int = Int.MAX_VALUE,
    overflow: android.text.TextUtils.TruncateAt? = null,
    linkColor: androidx.compose.ui.graphics.Color = androidx.compose.ui.graphics.Color(0xFF54A9EB), // Telegram-style blue
    mentionColor: androidx.compose.ui.graphics.Color = linkColor,
    enableLinks: Boolean = true, // 🔥 Включить кликабельные ссылки
    enableMentions: Boolean = false,
    onMentionClick: ((String) -> Unit)? = null,
    onClick: (() -> Unit)? = null, // 🔥 Обычный tap (selection mode в MessageBubble)
    onLongClick: (() -> Unit)? = null, // 🔥 Callback для long press (selection в MessageBubble)
    minHeightMultiplier: Float = 1.5f
) {
    val fontSizeValue = if (fontSize == androidx.compose.ui.unit.TextUnit.Unspecified) 15f 
        else fontSize.value
    
    // Минимальная высота для корректного отображения emoji
    val minHeight = (fontSizeValue * minHeightMultiplier).toInt()
    
    // Преобразуем FontWeight в Android typeface style
    val typefaceStyle = when (fontWeight) {
        androidx.compose.ui.text.font.FontWeight.Bold,
        androidx.compose.ui.text.font.FontWeight.ExtraBold,
        androidx.compose.ui.text.font.FontWeight.Black,
        androidx.compose.ui.text.font.FontWeight.SemiBold -> android.graphics.Typeface.BOLD
        androidx.compose.ui.text.font.FontWeight.Medium -> android.graphics.Typeface.NORMAL // Medium не поддерживается напрямую
        else -> android.graphics.Typeface.NORMAL
    }
    
    AndroidView(
        factory = { ctx ->
            AppleEmojiTextView(ctx).apply {
                setTextColor(color.toArgb())
                setTextSize(fontSizeValue)
                minimumHeight = (minHeight * ctx.resources.displayMetrics.density).toInt()
                setTypeface(typeface, typefaceStyle)
                // 🔥 Поддержка maxLines и ellipsize
                setMaxLines(maxLines)
                if (overflow != null) {
                    ellipsize = overflow
                }
                // 🔥 Включаем кликабельные ссылки с поддержкой long press
                if (enableLinks) {
                    setLinkColor(linkColor.toArgb())
                    enableClickableLinks(true, onLongClick)
                } else {
                    // 🔥 ВАЖНО: в selection mode полностью отключаем LinkMovementMethod,
                    // иначе тапы по тексту могут "съедаться" и не доходить до onClick.
                    enableClickableLinks(false, onLongClick)
                }
                setMentionColor(mentionColor.toArgb())
                enableMentionHighlight(enableMentions)
                setOnMentionClickListener(onMentionClick)
                // 🔥 Поддержка обычного tap (например, для selection mode)
                setOnClickListener(onClick?.let { click -> View.OnClickListener { click.invoke() } })
            }
        },
        update = { view ->
            view.setTextWithEmojis(text)
            view.setTextColor(color.toArgb())
            view.setTypeface(view.typeface, typefaceStyle)
            // 🔥 Обновляем maxLines и ellipsize
            view.maxLines = maxLines
            if (overflow != null) {
                view.ellipsize = overflow
            }
            // 🔥 Обновляем настройки ссылок с поддержкой long press
            if (enableLinks) {
                view.setLinkColor(linkColor.toArgb())
                view.enableClickableLinks(true, onLongClick)
            } else {
                // 🔥 ВАЖНО: в selection mode полностью отключаем LinkMovementMethod,
                // иначе тапы по тексту могут "съедаться" и не доходить до onClick.
                view.enableClickableLinks(false, onLongClick)
            }
            view.setMentionColor(mentionColor.toArgb())
            view.enableMentionHighlight(enableMentions)
            view.setOnMentionClickListener(onMentionClick)
            // 🔥 Обновляем tap callback, чтобы не было stale lambda
            view.setOnClickListener(onClick?.let { click -> View.OnClickListener { click.invoke() } })
        },
        modifier = modifier
    )
}

/**
 * Apple Emoji TextView - для отображения текста с PNG эмодзи
 * 🔥 Поддерживает:
 * - Реальные Unicode эмодзи (😀)
 * - Текстовый формат :emoji_1f600: (как в React Native версии)
 * - Кликабельные ссылки (URL, email, телефоны)
 */
class AppleEmojiTextView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = android.R.attr.textViewStyle
) : android.widget.TextView(context, attrs, defStyleAttr) {

    companion object {
        private val EMOJI_PATTERN = AppleEmojiEditTextView.EMOJI_PATTERN
        // 🔥 Паттерн для :emoji_XXXX: формата (из React Native)
        private val EMOJI_CODE_PATTERN = Pattern.compile(":emoji_([a-fA-F0-9_-]+):")
        private val bitmapCache = LruCache<String, Bitmap>(100)
        
        // 🔥 Паттерны для ссылок
        private val URL_PATTERN = Pattern.compile(
            "(https?://[\\w\\-._~:/?#\\[\\]@!$&'()*+,;=%]+)" +
            "|(www\\.[\\w\\-._~:/?#\\[\\]@!$&'()*+,;=%]+)" +
            "|([\\w\\-]+\\.(com|org|net|ru|io|dev|app|me|co|info|biz|edu|gov|uk|de|fr|jp|cn|br|in|au|ca|it|es|nl|se|no|fi|dk|pl|ua|kz|by)[\\w\\-._~:/?#\\[\\]@!$&'()*+,;=%]*)"
        )
        private val EMAIL_PATTERN = Patterns.EMAIL_ADDRESS
        private val PHONE_PATTERN = Pattern.compile(
            "\\+?[0-9][\\s\\-()0-9]{6,}[0-9]"
        )
        private val MENTION_PATTERN = Pattern.compile("(?<![A-Za-z0-9_])@[A-Za-z0-9_]{1,32}(?![A-Za-z0-9_])")
    }

    private var linkColorValue: Int = 0xFF54A9EB.toInt() // Default Telegram blue
    private var linksEnabled: Boolean = false
    private var mentionColorValue: Int = 0xFF54A9EB.toInt()
    private var mentionsEnabled: Boolean = false
    private var mentionClickCallback: ((String) -> Unit)? = null

    // 🔥 Long press callback для selection в MessageBubble
    var onLongClickCallback: (() -> Unit)? = null

    // 🔥 GestureDetector для обработки long press поверх LinkMovementMethod
    private val gestureDetector = GestureDetector(context, object : GestureDetector.SimpleOnGestureListener() {
        override fun onLongPress(e: MotionEvent) {
            onLongClickCallback?.invoke()
        }
    })

    init {
        // Отключаем лишние отступы шрифта для корректного отображения emoji
        includeFontPadding = false
    }

    /**
     * 🔥 Перехватываем touch события для обработки long press
     * GestureDetector обрабатывает long press, затем передаем событие parent для ссылок
     */
    override fun dispatchTouchEvent(event: MotionEvent): Boolean {
        // Позволяем GestureDetector обработать событие (для long press)
        gestureDetector.onTouchEvent(event)
        // Передаем событие дальше для обработки ссылок
        return super.dispatchTouchEvent(event)
    }

    /**
     * 🔥 Установить цвет для ссылок
     */
    fun setLinkColor(color: Int) {
        linkColorValue = color
    }

    fun setMentionColor(color: Int) {
        mentionColorValue = color
    }

    fun enableMentionHighlight(enable: Boolean) {
        mentionsEnabled = enable
        updateMovementMethod()
    }

    fun setOnMentionClickListener(listener: ((String) -> Unit)?) {
        mentionClickCallback = listener
        updateMovementMethod()
    }

    /**
     * 🔥 Включить/выключить кликабельные ссылки
     * @param enable - включить ссылки
     * @param onLongClick - callback для long press (для selection в MessageBubble)
     */
    fun enableClickableLinks(enable: Boolean, onLongClick: (() -> Unit)? = null) {
        linksEnabled = enable
        onLongClickCallback = onLongClick
        updateMovementMethod()
    }

    private fun updateMovementMethod() {
        val hasMentionClicks = mentionsEnabled && mentionClickCallback != null
        if (linksEnabled || hasMentionClicks) {
            movementMethod = LinkMovementMethod.getInstance()
            // Убираем highlight при клике
            highlightColor = android.graphics.Color.TRANSPARENT
        } else {
            movementMethod = null
        }
    }

    fun setTextWithEmojis(text: String) {
        // 🔥 Сначала заменяем :emoji_XXXX: на PNG изображения
        val spannable = SpannableStringBuilder(text)
        
        // Собираем все замены (чтобы не сбить индексы)
        data class EmojiMatch(val start: Int, val end: Int, val unified: String)
        val emojiMatches = mutableListOf<EmojiMatch>()
        
        // 1. Ищем :emoji_XXXX: формат
        val codeMatcher = EMOJI_CODE_PATTERN.matcher(text)
        while (codeMatcher.find()) {
            val unified = codeMatcher.group(1) ?: continue
            emojiMatches.add(EmojiMatch(codeMatcher.start(), codeMatcher.end(), unified))
        }
        
        // 2. Ищем реальные Unicode эмодзи
        val unicodeMatcher = EMOJI_PATTERN.matcher(text)
        while (unicodeMatcher.find()) {
            val emoji = unicodeMatcher.group()
            val unified = emojiToUnified(emoji)
            // Проверяем что этот диапазон не перекрывается с :emoji_XXXX:
            val overlaps = emojiMatches.any { 
                (unicodeMatcher.start() >= it.start && unicodeMatcher.start() < it.end) ||
                (unicodeMatcher.end() > it.start && unicodeMatcher.end() <= it.end)
            }
            if (!overlaps) {
                emojiMatches.add(EmojiMatch(unicodeMatcher.start(), unicodeMatcher.end(), unified))
            }
        }
        
        // 3. Сортируем по позиции в обратном порядке (чтобы не сбить индексы при замене)
        emojiMatches.sortByDescending { it.start }
        
        // 4. Применяем все замены
        for (match in emojiMatches) {
            val bitmap = loadEmojiBitmap(match.unified)
            if (bitmap != null) {
                val drawable = BitmapDrawable(resources, bitmap)
                val span = TelegramLikeEmojiSpan(drawable, paint.fontMetricsInt)
                
                // Для :emoji_XXXX: заменяем весь текст на пробел + span
                // Для Unicode эмодзи оставляем символ как есть
                if (match.end - match.start > 10) {
                    // Это :emoji_XXXX: формат - заменяем на один символ
                    spannable.replace(match.start, match.end, "\u200B") // Zero-width space
                    spannable.setSpan(span, match.start, match.start + 1, 
                        android.text.Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
                } else {
                    // Это Unicode эмодзи
                    spannable.setSpan(span, match.start, match.end, 
                        android.text.Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
                }
            } else if (match.end - match.start > 10) {
                // 🔥 Fallback: если PNG не найден, конвертируем :emoji_XXXX: в Unicode эмодзи
                val unicodeEmoji = unifiedToEmoji(match.unified)
                if (unicodeEmoji != null) {
                    spannable.replace(match.start, match.end, unicodeEmoji)
                }
            }
        }
        
        if (mentionsEnabled) {
            addMentionHighlights(spannable)
        }

        // 🔥 5. Добавляем кликабельные ссылки после обработки эмодзи
        if (linksEnabled) {
            addClickableLinks(spannable)
        }
        
        setText(spannable)
    }
    
    /**
     * 🔥 Добавляет кликабельные ссылки (URL, email, телефоны) в spannable
     */
    private enum class LinkType { URL, EMAIL, PHONE }

    private fun addMentionHighlights(spannable: SpannableStringBuilder) {
        val textStr = spannable.toString()
        val mentionMatcher = MENTION_PATTERN.matcher(textStr)
        while (mentionMatcher.find()) {
            val start = mentionMatcher.start()
            val end = mentionMatcher.end()
            val overlapsClickable = spannable.getSpans(start, end, ClickableSpan::class.java).isNotEmpty()
            if (overlapsClickable) continue
            val mentionText = textStr.substring(start, end).trim().trimStart('@')
            val callback = mentionClickCallback
            if (callback != null) {
                val clickableSpan = object : ClickableSpan() {
                    override fun onClick(widget: View) {
                        if (mentionText.isNotBlank()) {
                            callback.invoke(mentionText)
                        }
                    }

                    override fun updateDrawState(ds: TextPaint) {
                        super.updateDrawState(ds)
                        ds.color = mentionColorValue
                        ds.isUnderlineText = false
                    }
                }
                spannable.setSpan(
                    clickableSpan,
                    start,
                    end,
                    android.text.Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
                )
            } else {
                spannable.setSpan(
                    ForegroundColorSpan(mentionColorValue),
                    start,
                    end,
                    android.text.Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
                )
            }
        }
    }
    
    private fun addClickableLinks(spannable: SpannableStringBuilder) {
        val textStr = spannable.toString()
        
        // Собираем все найденные ссылки
        data class LinkMatch(val start: Int, val end: Int, val url: String, val type: LinkType)
        val linkMatches = mutableListOf<LinkMatch>()
        
        // 1. Ищем URL
        val urlMatcher = URL_PATTERN.matcher(textStr)
        while (urlMatcher.find()) {
            var url = urlMatcher.group()
            // Добавляем https:// если нет протокола
            if (!url.startsWith("http://") && !url.startsWith("https://")) {
                url = "https://$url"
            }
            linkMatches.add(LinkMatch(urlMatcher.start(), urlMatcher.end(), url, LinkType.URL))
        }
        
        // 2. Ищем Email
        val emailMatcher = EMAIL_PATTERN.matcher(textStr)
        while (emailMatcher.find()) {
            val email = emailMatcher.group()
            // Проверяем что не перекрывается с URL
            val overlaps = linkMatches.any { 
                (emailMatcher.start() >= it.start && emailMatcher.start() < it.end) ||
                (emailMatcher.end() > it.start && emailMatcher.end() <= it.end)
            }
            if (!overlaps) {
                linkMatches.add(LinkMatch(emailMatcher.start(), emailMatcher.end(), "mailto:$email", LinkType.EMAIL))
            }
        }
        
        // 3. Ищем телефоны
        val phoneMatcher = PHONE_PATTERN.matcher(textStr)
        while (phoneMatcher.find()) {
            val phone = phoneMatcher.group().replace("[\\s\\-()]".toRegex(), "")
            // Проверяем что не перекрывается с другими ссылками
            val overlaps = linkMatches.any { 
                (phoneMatcher.start() >= it.start && phoneMatcher.start() < it.end) ||
                (phoneMatcher.end() > it.start && phoneMatcher.end() <= it.end)
            }
            if (!overlaps && phone.length >= 7) {
                linkMatches.add(LinkMatch(phoneMatcher.start(), phoneMatcher.end(), "tel:$phone", LinkType.PHONE))
            }
        }
        
        // 4. Применяем ClickableSpan для каждой ссылки
        for (link in linkMatches) {
            val clickableSpan = object : ClickableSpan() {
                override fun onClick(widget: View) {
                    try {
                        val intent = Intent(Intent.ACTION_VIEW, Uri.parse(link.url))
                        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                        context.startActivity(intent)
                    } catch (e: Exception) {
                        // Если не удалось открыть ссылку, игнорируем
                        e.printStackTrace()
                    }
                }
                
                override fun updateDrawState(ds: TextPaint) {
                    super.updateDrawState(ds)
                    ds.color = linkColorValue
                    ds.isUnderlineText = false // Убираем подчёркивание (Telegram-style)
                }
            }
            
            spannable.setSpan(
                clickableSpan,
                link.start,
                link.end,
                android.text.Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
            )
        }
    }

    private fun loadEmojiBitmap(unified: String): Bitmap? {
        bitmapCache.get(unified)?.let { return it }
        
        return try {
            val path = "emoji/$unified.png"
            val inputStream = context.assets.open(path)
            val bitmap = BitmapFactory.decodeStream(inputStream)
            inputStream.close()
            bitmap?.let { bitmapCache.put(unified, it) }
            bitmap
        } catch (e: Exception) {
            null
        }
    }

    private fun emojiToUnified(emoji: String): String {
        val codePoints = emoji.codePoints().toArray()
        if (codePoints.isEmpty()) return ""

        val unifiedParts = ArrayList<String>(codePoints.size)
        for (codePoint in codePoints) {
            if (codePoint != 0xFE0F) {
                unifiedParts.add(String.format("%04x", codePoint))
            }
        }

        return unifiedParts.joinToString("-")
    }
    
    /**
     * 🔥 Конвертирует unified код (1f600) в Unicode эмодзи (😀)
     */
    private fun unifiedToEmoji(unified: String): String? {
        return try {
            val codePoints = unified.split("-").map { it.toInt(16) }
            String(codePoints.toIntArray(), 0, codePoints.size)
        } catch (e: Exception) {
            null
        }
    }
}
