package com.swoosh.microblog.data

/**
 * Parses #hashtag patterns from post text content.
 *
 * Rules:
 * - Hashtags start with # followed by at least one letter or digit
 * - Allowed characters: letters, digits, hyphens, underscores
 * - Hashtags must NOT be inside URLs (http://, https://, or www.)
 * - Leading # is stripped from the result
 * - Results are unique (case-preserved, deduped case-insensitively)
 * - Trailing hyphens/underscores are trimmed from tag names
 */
object HashtagParser {

    // Matches URLs so we can skip hashtags that appear inside them
    private val URL_PATTERN = Regex(
        """(?:https?://|www\.)\S+""",
        RegexOption.IGNORE_CASE
    )

    // Matches a hashtag: # followed by at least one word char (letter/digit),
    // then optionally more word chars or hyphens
    private val HASHTAG_PATTERN = Regex(
        """#([\w][\w-]*)""",
        RegexOption.IGNORE_CASE
    )

    /**
     * Extracts unique hashtag names from text content.
     * Returns tag names without the # prefix.
     */
    fun parse(text: String): List<String> {
        if (text.isBlank()) return emptyList()

        // Find all URL ranges so we can exclude hashtags inside URLs
        val urlRanges = URL_PATTERN.findAll(text).map { it.range }.toList()

        val seen = mutableSetOf<String>()
        val result = mutableListOf<String>()

        for (match in HASHTAG_PATTERN.findAll(text)) {
            // Skip if this hashtag is inside a URL
            if (urlRanges.any { urlRange -> match.range.first in urlRange }) {
                continue
            }

            val tagName = match.groupValues[1].trimEnd('-', '_')

            // Must have at least one character after trimming
            if (tagName.isEmpty()) continue

            // Deduplicate case-insensitively but preserve original casing
            val lowerTag = tagName.lowercase()
            if (lowerTag !in seen) {
                seen.add(lowerTag)
                result.add(tagName)
            }
        }

        return result
    }

    /**
     * Returns the ranges of hashtags in the text for highlighting.
     * Each range covers the full hashtag including the # prefix.
     */
    fun findHashtagRanges(text: String): List<IntRange> {
        if (text.isBlank()) return emptyList()

        val urlRanges = URL_PATTERN.findAll(text).map { it.range }.toList()

        return HASHTAG_PATTERN.findAll(text)
            .filter { match -> urlRanges.none { urlRange -> match.range.first in urlRange } }
            .map { it.range }
            .toList()
    }
}
