package com.swoosh.microblog.data

import com.swoosh.microblog.data.model.LinkPreview
import org.junit.Assert.*
import org.junit.Test

class PreviewHtmlBuilderTest {

    // --- Basic HTML structure ---

    @Test
    fun `build produces valid HTML document with DOCTYPE`() {
        val result = PreviewHtmlBuilder.build("Hello world")
        assertTrue(result.startsWith("<!DOCTYPE html>"))
    }

    @Test
    fun `build contains viewport meta tag`() {
        val result = PreviewHtmlBuilder.build("Hello")
        assertTrue(result.contains("<meta name=\"viewport\""))
        assertTrue(result.contains("width=device-width"))
    }

    @Test
    fun `build contains charset meta tag`() {
        val result = PreviewHtmlBuilder.build("Hello")
        assertTrue(result.contains("<meta charset=\"UTF-8\">"))
    }

    @Test
    fun `build wraps content in html and body tags`() {
        val result = PreviewHtmlBuilder.build("Hello")
        assertTrue(result.contains("<html>"))
        assertTrue(result.contains("</html>"))
        assertTrue(result.contains("<body>"))
        assertTrue(result.contains("</body>"))
    }

    @Test
    fun `build includes style block`() {
        val result = PreviewHtmlBuilder.build("Hello")
        assertTrue(result.contains("<style>"))
        assertTrue(result.contains("</style>"))
    }

    // --- Dark mode CSS ---

    @Test
    fun `build contains dark mode media query`() {
        val result = PreviewHtmlBuilder.build("Hello")
        assertTrue(result.contains("prefers-color-scheme: dark"))
    }

    @Test
    fun `dark mode sets dark background color`() {
        val result = PreviewHtmlBuilder.build("Hello")
        assertTrue(
            "Dark mode should set a dark background",
            result.contains("background: #1a1a2e")
        )
    }

    @Test
    fun `dark mode sets light text color`() {
        val result = PreviewHtmlBuilder.build("Hello")
        assertTrue(
            "Dark mode should set light text",
            result.contains("color: #e0e0e0")
        )
    }

    // --- Plain text rendering ---

    @Test
    fun `build with plain text wraps in paragraph tag`() {
        val result = PreviewHtmlBuilder.build("Hello world")
        assertTrue(result.contains("<p>Hello world</p>"))
    }

    @Test
    fun `build with multiline text creates multiple paragraphs`() {
        val result = PreviewHtmlBuilder.build("First paragraph\n\nSecond paragraph")
        assertTrue(result.contains("<p>First paragraph</p>"))
        assertTrue(result.contains("<p>Second paragraph</p>"))
    }

    @Test
    fun `build with single newlines converts to br tags`() {
        val result = PreviewHtmlBuilder.build("Line one\nLine two")
        assertTrue(result.contains("Line one<br>Line two"))
    }

    @Test
    fun `build preserves paragraph separation with double newlines`() {
        val html = PreviewHtmlBuilder.build("Para 1\n\nPara 2\n\nPara 3")
        // Should have 3 paragraph tags
        val paragraphCount = "<p>".toRegex().findAll(html).count()
        assertEquals(3, paragraphCount)
    }

    // --- Empty content ---

    @Test
    fun `build with empty text produces valid HTML`() {
        val result = PreviewHtmlBuilder.build("")
        assertTrue(result.contains("<!DOCTYPE html>"))
        assertTrue(result.contains("<body>"))
    }

    @Test
    fun `build with blank text does not produce paragraph tags`() {
        val result = PreviewHtmlBuilder.build("   ")
        assertFalse(result.contains("<p>"))
    }

    @Test
    fun `build with only whitespace produces valid document`() {
        val result = PreviewHtmlBuilder.build("  \n\n  \n  ")
        assertTrue(result.startsWith("<!DOCTYPE html>"))
    }

    // --- Image rendering ---

    @Test
    fun `build with image includes img tag`() {
        val result = PreviewHtmlBuilder.build("Text", imageUrl = "https://example.com/photo.jpg")
        assertTrue(result.contains("<img"))
        assertTrue(result.contains("https://example.com/photo.jpg"))
    }

    @Test
    fun `build with image wraps in figure tag`() {
        val result = PreviewHtmlBuilder.build("Text", imageUrl = "https://example.com/photo.jpg")
        assertTrue(result.contains("<figure"))
        assertTrue(result.contains("</figure>"))
    }

    @Test
    fun `build with image includes alt text`() {
        val result = PreviewHtmlBuilder.build("Text", imageUrl = "https://example.com/photo.jpg")
        assertTrue(result.contains("alt=\"Post image\""))
    }

    @Test
    fun `build with null image does not include img tag`() {
        val result = PreviewHtmlBuilder.build("Text", imageUrl = null)
        assertFalse(result.contains("<img"))
        assertFalse(result.contains("<figure"))
    }

    @Test
    fun `build with empty image does not include img tag`() {
        val result = PreviewHtmlBuilder.build("Text", imageUrl = "")
        assertFalse(result.contains("<img"))
    }

    @Test
    fun `image appears after text paragraphs`() {
        val result = PreviewHtmlBuilder.build("Some text", imageUrl = "https://example.com/img.jpg")
        val textIndex = result.indexOf("<p>Some text</p>")
        val imgIndex = result.indexOf("<img")
        assertTrue("Image should appear after text", imgIndex > textIndex)
    }

    // --- Link preview / bookmark card ---

    @Test
    fun `build with link preview includes bookmark card`() {
        val preview = LinkPreview(
            url = "https://example.com",
            title = "Example Site",
            description = "A great site",
            imageUrl = null
        )
        val result = PreviewHtmlBuilder.build("Text", linkPreview = preview)
        assertTrue(result.contains("bookmark-card"))
    }

    @Test
    fun `build with link preview includes title`() {
        val preview = LinkPreview(
            url = "https://example.com",
            title = "Example Title",
            description = null,
            imageUrl = null
        )
        val result = PreviewHtmlBuilder.build("Text", linkPreview = preview)
        assertTrue(result.contains("Example Title"))
    }

    @Test
    fun `build with link preview includes description`() {
        val preview = LinkPreview(
            url = "https://example.com",
            title = "Title",
            description = "A description of the page",
            imageUrl = null
        )
        val result = PreviewHtmlBuilder.build("Text", linkPreview = preview)
        assertTrue(result.contains("A description of the page"))
    }

    @Test
    fun `build with link preview includes URL`() {
        val preview = LinkPreview(
            url = "https://example.com/article",
            title = "Title",
            description = null,
            imageUrl = null
        )
        val result = PreviewHtmlBuilder.build("Text", linkPreview = preview)
        assertTrue(result.contains("https://example.com/article"))
    }

    @Test
    fun `build with link preview and image includes bookmark image`() {
        val preview = LinkPreview(
            url = "https://example.com",
            title = "Title",
            description = null,
            imageUrl = "https://example.com/og-image.jpg"
        )
        val result = PreviewHtmlBuilder.build("Text", linkPreview = preview)
        assertTrue(result.contains("bookmark-image"))
        assertTrue(result.contains("https://example.com/og-image.jpg"))
    }

    @Test
    fun `build with link preview without image does not include bookmark-image in content`() {
        val preview = LinkPreview(
            url = "https://example.com",
            title = "Title",
            description = "Desc",
            imageUrl = null
        )
        val result = PreviewHtmlBuilder.buildContentHtml("Text", null, preview)
        assertFalse(result.contains("bookmark-image"))
    }

    @Test
    fun `build with null link preview does not include bookmark card in content`() {
        val result = PreviewHtmlBuilder.buildContentHtml("Text", null, null)
        assertFalse(result.contains("bookmark-card"))
    }

    @Test
    fun `bookmark card appears after text and image in content`() {
        val preview = LinkPreview(
            url = "https://example.com",
            title = "Title",
            description = null,
            imageUrl = null
        )
        val result = PreviewHtmlBuilder.buildContentHtml(
            "Some text",
            "https://example.com/img.jpg",
            preview
        )
        val textIndex = result.indexOf("<p>Some text</p>")
        val imgIndex = result.indexOf("<figure")
        val bookmarkIndex = result.indexOf("bookmark-card")
        assertTrue("Text should come first", textIndex < imgIndex)
        assertTrue("Image should come before bookmark", imgIndex < bookmarkIndex)
    }

    // --- HTML escaping ---

    @Test
    fun `escapeHtml escapes ampersand`() {
        assertEquals("&amp;", PreviewHtmlBuilder.escapeHtml("&"))
    }

    @Test
    fun `escapeHtml escapes less-than`() {
        assertEquals("&lt;", PreviewHtmlBuilder.escapeHtml("<"))
    }

    @Test
    fun `escapeHtml escapes greater-than`() {
        assertEquals("&gt;", PreviewHtmlBuilder.escapeHtml(">"))
    }

    @Test
    fun `escapeHtml escapes double quotes`() {
        assertEquals("&quot;", PreviewHtmlBuilder.escapeHtml("\""))
    }

    @Test
    fun `escapeHtml escapes single quotes`() {
        assertEquals("&#39;", PreviewHtmlBuilder.escapeHtml("'"))
    }

    @Test
    fun `escapeHtml handles combined special characters`() {
        assertEquals(
            "&lt;script&gt;alert(&#39;xss&#39;)&lt;/script&gt;",
            PreviewHtmlBuilder.escapeHtml("<script>alert('xss')</script>")
        )
    }

    @Test
    fun `escapeHtml leaves normal text unchanged`() {
        assertEquals("Hello world", PreviewHtmlBuilder.escapeHtml("Hello world"))
    }

    @Test
    fun `escapeHtml handles empty string`() {
        assertEquals("", PreviewHtmlBuilder.escapeHtml(""))
    }

    @Test
    fun `build escapes HTML in text content`() {
        val result = PreviewHtmlBuilder.build("<script>alert('xss')</script>")
        assertFalse("Should not contain unescaped script tag", result.contains("<script>alert"))
        assertTrue(result.contains("&lt;script&gt;"))
    }

    @Test
    fun `build escapes HTML in link preview title`() {
        val preview = LinkPreview(
            url = "https://example.com",
            title = "<b>Bold</b>",
            description = null,
            imageUrl = null
        )
        val result = PreviewHtmlBuilder.build("Text", linkPreview = preview)
        assertTrue(result.contains("&lt;b&gt;Bold&lt;/b&gt;"))
    }

    // --- wrapExistingHtml ---

    @Test
    fun `wrapExistingHtml produces valid HTML document`() {
        val result = PreviewHtmlBuilder.wrapExistingHtml("<p>Hello</p>")
        assertTrue(result.startsWith("<!DOCTYPE html>"))
        assertTrue(result.contains("<p>Hello</p>"))
    }

    @Test
    fun `wrapExistingHtml includes same styling as build`() {
        val fromBuild = PreviewHtmlBuilder.build("Hello")
        val fromWrap = PreviewHtmlBuilder.wrapExistingHtml("<p>Hello</p>")

        // Both should contain the same CSS
        assertTrue(fromBuild.contains("bookmark-card"))
        assertTrue(fromWrap.contains("bookmark-card"))
        assertTrue(fromBuild.contains("prefers-color-scheme: dark"))
        assertTrue(fromWrap.contains("prefers-color-scheme: dark"))
    }

    @Test
    fun `wrapExistingHtml preserves raw HTML content`() {
        val html = "<h1>Title</h1><p>Paragraph with <strong>bold</strong> text.</p>"
        val result = PreviewHtmlBuilder.wrapExistingHtml(html)
        assertTrue(result.contains(html))
    }

    @Test
    fun `wrapExistingHtml handles empty HTML`() {
        val result = PreviewHtmlBuilder.wrapExistingHtml("")
        assertTrue(result.startsWith("<!DOCTYPE html>"))
    }

    // --- buildContentHtml (internal) ---

    @Test
    fun `buildContentHtml with all content types produces all sections`() {
        val preview = LinkPreview(
            url = "https://example.com",
            title = "Title",
            description = "Desc",
            imageUrl = "https://example.com/image.jpg"
        )
        val result = PreviewHtmlBuilder.buildContentHtml(
            text = "Hello world",
            imageUrl = "https://example.com/photo.jpg",
            linkPreview = preview
        )
        assertTrue("Should contain paragraph", result.contains("<p>Hello world</p>"))
        assertTrue("Should contain feature image", result.contains("photo.jpg"))
        assertTrue("Should contain bookmark card", result.contains("bookmark-card"))
        assertTrue("Should contain bookmark image", result.contains("bookmark-image"))
    }

    @Test
    fun `buildContentHtml with no content produces empty string`() {
        val result = PreviewHtmlBuilder.buildContentHtml(
            text = "",
            imageUrl = null,
            linkPreview = null
        )
        assertEquals("", result)
    }

    // --- buildBookmarkCard (internal) ---

    @Test
    fun `buildBookmarkCard includes all fields when present`() {
        val preview = LinkPreview(
            url = "https://example.com",
            title = "Test Title",
            description = "Test Description",
            imageUrl = "https://example.com/thumb.jpg"
        )
        val result = PreviewHtmlBuilder.buildBookmarkCard(preview)
        assertTrue(result.contains("bookmark-card"))
        assertTrue(result.contains("bookmark-image"))
        assertTrue(result.contains("bookmark-title"))
        assertTrue(result.contains("Test Title"))
        assertTrue(result.contains("bookmark-description"))
        assertTrue(result.contains("Test Description"))
        assertTrue(result.contains("bookmark-url"))
        assertTrue(result.contains("https://example.com"))
    }

    @Test
    fun `buildBookmarkCard without image omits image tag`() {
        val preview = LinkPreview(
            url = "https://example.com",
            title = "Title",
            description = null,
            imageUrl = null
        )
        val result = PreviewHtmlBuilder.buildBookmarkCard(preview)
        assertFalse(result.contains("bookmark-image"))
        assertFalse(result.contains("<img"))
    }

    @Test
    fun `buildBookmarkCard without title omits title div`() {
        val preview = LinkPreview(
            url = "https://example.com",
            title = null,
            description = "Desc",
            imageUrl = null
        )
        val result = PreviewHtmlBuilder.buildBookmarkCard(preview)
        assertFalse(result.contains("bookmark-title"))
    }

    @Test
    fun `buildBookmarkCard without description omits description div`() {
        val preview = LinkPreview(
            url = "https://example.com",
            title = "Title",
            description = null,
            imageUrl = null
        )
        val result = PreviewHtmlBuilder.buildBookmarkCard(preview)
        assertFalse(result.contains("bookmark-description"))
    }

    @Test
    fun `buildBookmarkCard always includes URL`() {
        val preview = LinkPreview(
            url = "https://example.com/article",
            title = null,
            description = null,
            imageUrl = null
        )
        val result = PreviewHtmlBuilder.buildBookmarkCard(preview)
        assertTrue(result.contains("bookmark-url"))
        assertTrue(result.contains("https://example.com/article"))
    }

    // --- CSS styling ---

    @Test
    fun `template includes responsive image styling`() {
        val result = PreviewHtmlBuilder.build("Test")
        assertTrue(result.contains("max-width: 100%"))
    }

    @Test
    fun `template includes responsive body max-width`() {
        val result = PreviewHtmlBuilder.build("Test")
        assertTrue(result.contains("max-width: 600px"))
    }

    @Test
    fun `template includes system font stack`() {
        val result = PreviewHtmlBuilder.build("Test")
        assertTrue(result.contains("-apple-system"))
        assertTrue(result.contains("sans-serif"))
    }

    @Test
    fun `template includes border-radius for bookmark card`() {
        val result = PreviewHtmlBuilder.build("Test")
        assertTrue(result.contains("border-radius: 8px"))
    }
}
