package com.anypreta.bountyboard.ui.components

import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.LinkAnnotation
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.TextLinkStyles
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.text.withLink
import com.anypreta.bountyboard.ui.theme.BB

/**
 * Renders server-sanitized rich text (or plain text) with **clickable links** —
 * both `<a href>` anchors and bare http(s)/www URLs become tappable, opening in the
 * browser via the platform UriHandler. Used for chat messages, comments, and
 * task descriptions.
 */
@Composable
fun RichText(
    text: String,
    modifier: Modifier = Modifier,
    color: Color = BB.colors.text,
    linkColor: Color = BB.colors.accent,
    style: TextStyle = LocalTextStyle.current,
    maxLines: Int = Int.MAX_VALUE,
    overflow: TextOverflow = TextOverflow.Clip,
) {
    val tokens = remember(text) { tokenize(text) }
    val annotated = buildAnnotatedString {
        val linkStyles = TextLinkStyles(
            style = SpanStyle(color = linkColor, textDecoration = TextDecoration.Underline),
        )
        tokens.forEach { t ->
            when (t) {
                is Token.Plain -> append(t.text)
                is Token.Link -> withLink(LinkAnnotation.Url(t.url, linkStyles)) { append(t.label) }
            }
        }
    }
    Text(
        annotated,
        modifier = modifier,
        color = color,
        style = style,
        maxLines = maxLines,
        overflow = overflow,
    )
}

private sealed interface Token {
    data class Plain(val text: String) : Token
    data class Link(val label: String, val url: String) : Token
}

private val anchorRegex =
    Regex("""<a\b[^>]*?href\s*=\s*["']([^"']+)["'][^>]*>(.*?)</a>""", RegexOption.DOT_MATCHES_ALL)
private val urlRegex = Regex("""(https?://[^\s<]+)|(www\.[^\s<]+)""")

private fun tokenize(html: String): List<Token> {
    val out = mutableListOf<Token>()
    var last = 0
    for (m in anchorRegex.findAll(html)) {
        if (m.range.first > last) {
            addPlainWithUrls(out, stripTags(html.substring(last, m.range.first)))
        }
        val url = normalizeUrl(m.groupValues[1])
        val label = stripTags(m.groupValues[2]).ifBlank { m.groupValues[1] }
        out += Token.Link(label, url)
        last = m.range.last + 1
    }
    if (last < html.length) {
        addPlainWithUrls(out, stripTags(html.substring(last)))
    }
    return out.ifEmpty { listOf(Token.Plain(stripTags(html))) }
}

/** Split a plain string into text + auto-detected bare-URL link tokens. */
private fun addPlainWithUrls(out: MutableList<Token>, text: String) {
    if (text.isEmpty()) return
    var last = 0
    for (m in urlRegex.findAll(text)) {
        if (m.range.first > last) out += Token.Plain(text.substring(last, m.range.first))
        val raw = m.value.trimEnd('.', ',', ')', ']', '!', '?', ';', ':')
        out += Token.Link(raw, normalizeUrl(raw))
        last = m.range.first + raw.length
    }
    if (last < text.length) out += Token.Plain(text.substring(last))
}

private fun normalizeUrl(u: String): String =
    if (u.startsWith("http://") || u.startsWith("https://")) u else "https://$u"

private fun stripTags(s: String): String =
    s.replace(Regex("<br\\s*/?>"), "\n")
        .replace(Regex("</p>|</li>|</blockquote>"), "\n")
        .replace(Regex("<[^>]+>"), "")
        .replace("&amp;", "&").replace("&lt;", "<").replace("&gt;", ">")
        .replace("&quot;", "\"").replace("&#39;", "'").replace("&nbsp;", " ")
