package com.swoosh.microblog.data

import org.junit.Assert.*
import org.junit.Test

class HashtagParserTest {

    // --- Basic parsing ---

    @Test
    fun `parse extracts single hashtag`() {
        val tags = HashtagParser.parse("Hello #world")
        assertEquals(listOf("world"), tags)
    }

    @Test
    fun `parse extracts multiple hashtags`() {
        val tags = HashtagParser.parse("Hello #world #kotlin #android")
        assertEquals(listOf("world", "kotlin", "android"), tags)
    }

    @Test
    fun `parse returns empty list for text without hashtags`() {
        val tags = HashtagParser.parse("Hello world, no tags here!")
        assertTrue(tags.isEmpty())
    }

    @Test
    fun `parse returns empty list for blank text`() {
        val tags = HashtagParser.parse("")
        assertTrue(tags.isEmpty())
        val tags2 = HashtagParser.parse("   ")
        assertTrue(tags2.isEmpty())
    }

    @Test
    fun `parse strips hash prefix from results`() {
        val tags = HashtagParser.parse("#kotlin")
        assertEquals("kotlin", tags.first())
        assertFalse(tags.first().startsWith("#"))
    }

    // --- Position handling ---

    @Test
    fun `parse handles hashtag at start of text`() {
        val tags = HashtagParser.parse("#hello this is a post")
        assertEquals(listOf("hello"), tags)
    }

    @Test
    fun `parse handles hashtag at end of text`() {
        val tags = HashtagParser.parse("This is a post #hello")
        assertEquals(listOf("hello"), tags)
    }

    @Test
    fun `parse handles hashtag in middle of text`() {
        val tags = HashtagParser.parse("This is a #hello post")
        assertEquals(listOf("hello"), tags)
    }

    @Test
    fun `parse handles hashtags on multiple lines`() {
        val tags = HashtagParser.parse("Line one #tag1\nLine two #tag2\nLine three #tag3")
        assertEquals(listOf("tag1", "tag2", "tag3"), tags)
    }

    // --- Special characters ---

    @Test
    fun `parse handles CamelCase hashtags`() {
        val tags = HashtagParser.parse("Hello #CamelCase and #helloWorld")
        assertEquals(listOf("CamelCase", "helloWorld"), tags)
    }

    @Test
    fun `parse handles hyphenated hashtags`() {
        val tags = HashtagParser.parse("Check out #hello-world")
        assertEquals(listOf("hello-world"), tags)
    }

    @Test
    fun `parse handles underscored hashtags`() {
        val tags = HashtagParser.parse("Check out #hello_world")
        assertEquals(listOf("hello_world"), tags)
    }

    @Test
    fun `parse handles hashtags with digits`() {
        val tags = HashtagParser.parse("Check out #tag123 and #2024goals")
        assertEquals(listOf("tag123", "2024goals"), tags)
    }

    @Test
    fun `parse trims trailing hyphens from tag names`() {
        val tags = HashtagParser.parse("Check #hello- there")
        assertEquals(listOf("hello"), tags)
    }

    @Test
    fun `parse trims trailing underscores from tag names`() {
        val tags = HashtagParser.parse("Check #hello_ there")
        assertEquals(listOf("hello"), tags)
    }

    // --- Deduplication ---

    @Test
    fun `parse deduplicates tags case-insensitively`() {
        val tags = HashtagParser.parse("#Hello #hello #HELLO")
        assertEquals(1, tags.size)
        assertEquals("Hello", tags.first()) // Preserves first occurrence casing
    }

    @Test
    fun `parse preserves order of unique tags`() {
        val tags = HashtagParser.parse("#beta #alpha #gamma")
        assertEquals(listOf("beta", "alpha", "gamma"), tags)
    }

    // --- URL exclusion ---

    @Test
    fun `parse ignores hashtags inside URLs with https`() {
        val tags = HashtagParser.parse("Visit https://example.com/page#section and also #realtag")
        assertEquals(listOf("realtag"), tags)
    }

    @Test
    fun `parse ignores hashtags inside URLs with http`() {
        val tags = HashtagParser.parse("Visit http://example.com/path#anchor and #realtag")
        assertEquals(listOf("realtag"), tags)
    }

    @Test
    fun `parse ignores hashtags inside www URLs`() {
        val tags = HashtagParser.parse("Visit www.example.com/path#anchor for more #info")
        assertEquals(listOf("info"), tags)
    }

    @Test
    fun `parse handles URL followed by real hashtag`() {
        val tags = HashtagParser.parse("https://example.com #kotlin")
        assertEquals(listOf("kotlin"), tags)
    }

    // --- Edge cases ---

    @Test
    fun `parse ignores lone hash symbol`() {
        val tags = HashtagParser.parse("Use # wisely")
        assertTrue(tags.isEmpty())
    }

    @Test
    fun `parse handles adjacent hashtags`() {
        val tags = HashtagParser.parse("#one#two#three")
        // #one is parsed, then #two and #three appear inside #one's text or as separate matches
        assertTrue(tags.contains("one"))
    }

    @Test
    fun `parse handles hashtag with punctuation after it`() {
        val tags = HashtagParser.parse("Check #kotlin, it's great! And #android.")
        assertTrue(tags.contains("kotlin"))
        assertTrue(tags.contains("android"))
    }

    @Test
    fun `parse handles hashtag in parentheses`() {
        val tags = HashtagParser.parse("Languages (#kotlin) are great")
        assertTrue(tags.contains("kotlin"))
    }

    @Test
    fun `parse handles real-world microblog post`() {
        val text = "Just shipped a new feature for Swoosh! #android #ghostcms #opensource\n\nCheck it out at https://github.com/example/swoosh#readme"
        val tags = HashtagParser.parse(text)
        assertEquals(3, tags.size)
        assertTrue(tags.contains("android"))
        assertTrue(tags.contains("ghostcms"))
        assertTrue(tags.contains("opensource"))
        // Should NOT include 'readme' from the URL
        assertFalse(tags.contains("readme"))
    }

    // --- findHashtagRanges ---

    @Test
    fun `findHashtagRanges returns correct ranges`() {
        val text = "Hello #world and #kotlin"
        val ranges = HashtagParser.findHashtagRanges(text)
        assertEquals(2, ranges.size)
        assertEquals("#world", text.substring(ranges[0]))
        assertEquals("#kotlin", text.substring(ranges[1]))
    }

    @Test
    fun `findHashtagRanges returns empty for no hashtags`() {
        val ranges = HashtagParser.findHashtagRanges("No hashtags here")
        assertTrue(ranges.isEmpty())
    }

    @Test
    fun `findHashtagRanges excludes URL hashtags`() {
        val text = "Visit https://example.com#section and #realtag"
        val ranges = HashtagParser.findHashtagRanges(text)
        assertEquals(1, ranges.size)
        assertEquals("#realtag", text.substring(ranges[0]))
    }

    @Test
    fun `findHashtagRanges returns empty for blank text`() {
        val ranges = HashtagParser.findHashtagRanges("")
        assertTrue(ranges.isEmpty())
    }
}
