package com.rssuper.models

import com.squareup.moshi.Moshi
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotNull
import org.junit.Assert.assertNull
import org.junit.Before
import org.junit.Test
import java.util.Date

class SearchResultTest {

    private lateinit var moshi: Moshi
    private lateinit var adapter: com.squareup.moshi.JsonAdapter<SearchResult>

    @Before
    fun setup() {
        moshi = Moshi.Builder()
            .add(KotlinJsonAdapterFactory())
            .build()
        adapter = moshi.adapter(SearchResult::class.java)
    }

    @Test
    fun testArticleSerialization() {
        val result = SearchResult(
            id = "article-1",
            type = SearchResultType.ARTICLE,
            title = "Test Article",
            snippet = "This is a snippet",
            link = "https://example.com/article",
            feedTitle = "Tech News",
            published = Date(1672531200000),
            score = 0.95
        )

        val json = adapter.toJson(result)
        assertNotNull(json)
    }

    @Test
    fun testFeedSerialization() {
        val result = SearchResult(
            id = "feed-1",
            type = SearchResultType.FEED,
            title = "Tech News Feed",
            snippet = "Technology news and updates",
            link = "https://example.com",
            score = 0.85
        )

        val json = adapter.toJson(result)
        assertNotNull(json)
    }

    @Test
    fun testArticleDeserialization() {
        val json = """{
            "id": "article-1",
            "type": "article",
            "title": "Test Article",
            "snippet": "This is a snippet",
            "link": "https://example.com/article",
            "feedTitle": "Tech News",
            "published": 1672531200000,
            "score": 0.95
        }"""

        val result = adapter.fromJson(json)
        assertNotNull(result)
        assertEquals("article-1", result?.id)
        assertEquals(SearchResultType.ARTICLE, result?.type)
        assertEquals("Test Article", result?.title)
        assertEquals("This is a snippet", result?.snippet)
    }

    @Test
    fun testFeedDeserialization() {
        val json = """{
            "id": "feed-1",
            "type": "feed",
            "title": "Tech News Feed",
            "snippet": "Technology news and updates",
            "link": "https://example.com",
            "score": 0.85
        }"""

        val result = adapter.fromJson(json)
        assertNotNull(result)
        assertEquals("feed-1", result?.id)
        assertEquals(SearchResultType.FEED, result?.type)
    }

    @Test
    fun testOptionalFieldsNull() {
        val json = """{
            "id": "article-1",
            "type": "article",
            "title": "Test Article"
        }"""

        val result = adapter.fromJson(json)
        assertNotNull(result)
        assertNull(result?.snippet)
        assertNull(result?.link)
        assertNull(result?.feedTitle)
        assertNull(result?.published)
        assertNull(result?.score)
    }

    @Test
    fun testCopy() {
        val original = SearchResult(
            id = "article-1",
            type = SearchResultType.ARTICLE,
            title = "Original Title"
        )

        val modified = original.copy(title = "Modified Title", score = 0.99)

        assertEquals("article-1", modified.id)
        assertEquals(SearchResultType.ARTICLE, modified.type)
        assertEquals("Modified Title", modified.title)
        assertEquals(0.99, modified.score, 0.001)
    }

    @Test
    fun testEqualsAndHashCode() {
        val result1 = SearchResult(id = "article-1", type = SearchResultType.ARTICLE, title = "Test")
        val result2 = SearchResult(id = "article-1", type = SearchResultType.ARTICLE, title = "Test")
        val result3 = SearchResult(id = "article-2", type = SearchResultType.ARTICLE, title = "Test")

        assertEquals(result1, result2)
        assertEquals(result1.hashCode(), result2.hashCode())
        assert(result1 != result3)
    }

    @Test
    fun testToString() {
        val result = SearchResult(
            id = "article-1",
            type = SearchResultType.ARTICLE,
            title = "Test Article",
            score = 0.95
        )

        val toString = result.toString()
        assertNotNull(toString)
        assert(toString.contains("id=article-1"))
        assert(toString.contains("title=Test Article"))
    }
}
