package com.swoosh.microblog.data.model

import com.google.gson.Gson
import org.junit.Assert.*
import org.junit.Test

class GhostModelsTest {

    private val gson = Gson()

    // --- LocalPost defaults ---

    @Test
    fun `LocalPost default status is DRAFT`() {
        val post = LocalPost()
        assertEquals(PostStatus.DRAFT, post.status)
    }

    @Test
    fun `LocalPost default queueStatus is NONE`() {
        val post = LocalPost()
        assertEquals(QueueStatus.NONE, post.queueStatus)
    }

    @Test
    fun `LocalPost default title is empty`() {
        val post = LocalPost()
        assertEquals("", post.title)
    }

    @Test
    fun `LocalPost default content is empty`() {
        val post = LocalPost()
        assertEquals("", post.content)
    }

    @Test
    fun `LocalPost default ghostId is null`() {
        val post = LocalPost()
        assertNull(post.ghostId)
    }

    @Test
    fun `LocalPost default imageUri is null`() {
        val post = LocalPost()
        assertNull(post.imageUri)
    }

    @Test
    fun `LocalPost default imageUris is null`() {
        val post = LocalPost()
        assertNull(post.imageUris)
    }

    @Test
    fun `LocalPost default uploadedImageUrls is null`() {
        val post = LocalPost()
        assertNull(post.uploadedImageUrls)
    }

    @Test
    fun `LocalPost createdAt is set on construction`() {
        val before = System.currentTimeMillis()
        val post = LocalPost()
        val after = System.currentTimeMillis()
        assertTrue(post.createdAt in before..after)
    }

    // --- GhostPost defaults ---

    @Test
    fun `GhostPost default visibility is public`() {
        val post = GhostPost()
        assertEquals("public", post.visibility)
    }

    @Test
    fun `GhostPost all fields default to null except visibility and featured`() {
        val post = GhostPost()
        assertNull(post.id)
        assertNull(post.title)
        assertNull(post.slug)
        assertNull(post.url)
        assertNull(post.html)
        assertNull(post.plaintext)
        assertNull(post.mobiledoc)
        assertNull(post.status)
        assertEquals(false, post.featured)
        assertNull(post.feature_image)
        assertNull(post.feature_image_alt)
        assertNull(post.created_at)
        assertNull(post.updated_at)
        assertNull(post.published_at)
        assertNull(post.custom_excerpt)
        assertNull(post.authors)
        assertNull(post.reading_time)
    }

    @Test
    fun `GhostPost reading_time deserializes from JSON`() {
        val json = """{"id":"test","reading_time":3}"""
        val post = gson.fromJson(json, GhostPost::class.java)
        assertEquals(3, post.reading_time)
    }

    // --- FeedPost ---

    @Test
    fun `FeedPost default isLocal is false`() {
        val post = FeedPost(
            title = "Test",
            textContent = "Content",
            htmlContent = null,
            imageUrl = null,
            linkUrl = null,
            linkTitle = null,
            linkDescription = null,
            linkImageUrl = null,
            status = "published",
            publishedAt = null,
            createdAt = null,
            updatedAt = null
        )
        assertFalse(post.isLocal)
    }

    @Test
    fun `FeedPost default queueStatus is NONE`() {
        val post = FeedPost(
            title = "Test",
            textContent = "Content",
            htmlContent = null,
            imageUrl = null,
            linkUrl = null,
            linkTitle = null,
            linkDescription = null,
            linkImageUrl = null,
            status = "published",
            publishedAt = null,
            createdAt = null,
            updatedAt = null
        )
        assertEquals(QueueStatus.NONE, post.queueStatus)
    }

    @Test
    fun `FeedPost default imageUrls is empty`() {
        val post = FeedPost(
            title = "Test",
            textContent = "Content",
            htmlContent = null,
            imageUrl = null,
            linkUrl = null,
            linkTitle = null,
            linkDescription = null,
            linkImageUrl = null,
            status = "published",
            publishedAt = null,
            createdAt = null,
            updatedAt = null
        )
        assertTrue(post.imageUrls.isEmpty())
    }

    @Test
    fun `FeedPost imageUrls stores multiple URLs`() {
        val urls = listOf("https://example.com/img1.jpg", "https://example.com/img2.jpg")
        val post = FeedPost(
            title = "Test",
            textContent = "Content",
            htmlContent = null,
            imageUrl = "https://example.com/img1.jpg",
            imageUrls = urls,
            linkUrl = null,
            linkTitle = null,
            linkDescription = null,
            linkImageUrl = null,
            status = "published",
            publishedAt = null,
            createdAt = null,
            updatedAt = null
        )
        assertEquals(2, post.imageUrls.size)
        assertEquals("https://example.com/img1.jpg", post.imageUrls[0])
        assertEquals("https://example.com/img2.jpg", post.imageUrls[1])
    }

    // --- GSON serialization ---

    @Test
    fun `GhostPost serializes to JSON correctly`() {
        val post = GhostPost(
            id = "abc123",
            title = "Test Post",
            status = "published",
            visibility = "public"
        )
        val json = gson.toJson(post)
        assertTrue(json.contains("\"id\":\"abc123\""))
        assertTrue(json.contains("\"title\":\"Test Post\""))
        assertTrue(json.contains("\"status\":\"published\""))
    }

    @Test
    fun `GhostPost deserializes from JSON correctly`() {
        val json = """{"id":"xyz","title":"Hello","status":"draft","visibility":"public"}"""
        val post = gson.fromJson(json, GhostPost::class.java)
        assertEquals("xyz", post.id)
        assertEquals("Hello", post.title)
        assertEquals("draft", post.status)
        assertEquals("public", post.visibility)
    }

    @Test
    fun `GhostPost deserializes with missing optional fields`() {
        val json = """{"id":"test"}"""
        val post = gson.fromJson(json, GhostPost::class.java)
        assertEquals("test", post.id)
        assertNull(post.title)
        assertNull(post.html)
        assertNull(post.status)
    }

    @Test
    fun `PostsResponse deserializes with posts and pagination`() {
        val json = """{
            "posts": [{"id": "1", "title": "First"}],
            "meta": {"pagination": {"page": 1, "limit": 15, "pages": 3, "total": 42, "next": 2, "prev": null}}
        }"""
        val response = gson.fromJson(json, PostsResponse::class.java)
        assertEquals(1, response.posts.size)
        assertEquals("1", response.posts[0].id)
        assertEquals(1, response.meta?.pagination?.page)
        assertEquals(3, response.meta?.pagination?.pages)
        assertEquals(42, response.meta?.pagination?.total)
        assertEquals(2, response.meta?.pagination?.next)
        assertNull(response.meta?.pagination?.prev)
    }

    @Test
    fun `PostWrapper wraps posts for API request`() {
        val wrapper = PostWrapper(listOf(GhostPost(title = "New Post", status = "draft")))
        val json = gson.toJson(wrapper)
        assertTrue(json.contains("\"posts\""))
        assertTrue(json.contains("\"New Post\""))
    }

    @Test
    fun `Author deserializes correctly`() {
        val json = """{"id":"author1","name":"John"}"""
        val author = gson.fromJson(json, Author::class.java)
        assertEquals("author1", author.id)
        assertEquals("John", author.name)
    }

    @Test
    fun `Pagination with no next page`() {
        val json = """{"page":3,"limit":15,"pages":3,"total":45,"next":null,"prev":2}"""
        val pagination = gson.fromJson(json, Pagination::class.java)
        assertNull(pagination.next)
        assertEquals(2, pagination.prev)
        assertEquals(3, pagination.page)
    }

    // --- Enum values ---

    @Test
    fun `PostStatus has exactly 4 values`() {
        assertEquals(4, PostStatus.values().size)
    }

    @Test
    fun `QueueStatus has exactly 6 values`() {
        assertEquals(6, QueueStatus.values().size)
    }

    @Test
    fun `PostStatus valueOf works for all values`() {
        assertEquals(PostStatus.DRAFT, PostStatus.valueOf("DRAFT"))
        assertEquals(PostStatus.PUBLISHED, PostStatus.valueOf("PUBLISHED"))
        assertEquals(PostStatus.SCHEDULED, PostStatus.valueOf("SCHEDULED"))
        assertEquals(PostStatus.SENT, PostStatus.valueOf("SENT"))
    }

    @Test
    fun `QueueStatus valueOf works for all values`() {
        assertEquals(QueueStatus.NONE, QueueStatus.valueOf("NONE"))
        assertEquals(QueueStatus.QUEUED_PUBLISH, QueueStatus.valueOf("QUEUED_PUBLISH"))
        assertEquals(QueueStatus.QUEUED_SCHEDULED, QueueStatus.valueOf("QUEUED_SCHEDULED"))
        assertEquals(QueueStatus.QUEUED_EMAIL_ONLY, QueueStatus.valueOf("QUEUED_EMAIL_ONLY"))
        assertEquals(QueueStatus.UPLOADING, QueueStatus.valueOf("UPLOADING"))
        assertEquals(QueueStatus.FAILED, QueueStatus.valueOf("FAILED"))
    }

    // --- LinkPreview ---

    @Test
    fun `LinkPreview stores all fields correctly`() {
        val preview = LinkPreview(
            url = "https://example.com",
            title = "Example Title",
            description = "A description",
            imageUrl = "https://example.com/img.png"
        )
        assertEquals("https://example.com", preview.url)
        assertEquals("Example Title", preview.title)
        assertEquals("A description", preview.description)
        assertEquals("https://example.com/img.png", preview.imageUrl)
    }

    @Test
    fun `LinkPreview allows null optional fields`() {
        val preview = LinkPreview(
            url = "https://example.com",
            title = null,
            description = null,
            imageUrl = null
        )
        assertNull(preview.title)
        assertNull(preview.description)
        assertNull(preview.imageUrl)
    }

    // --- Alt text ---

    @Test
    fun `LocalPost default imageAlt is null`() {
        val post = LocalPost()
        assertNull(post.imageAlt)
    }

    @Test
    fun `LocalPost stores imageAlt`() {
        val post = LocalPost(imageAlt = "A sunset over the ocean")
        assertEquals("A sunset over the ocean", post.imageAlt)
    }

    @Test
    fun `GhostPost default feature_image_alt is null`() {
        val post = GhostPost()
        assertNull(post.feature_image_alt)
    }

    @Test
    fun `GhostPost stores feature_image_alt`() {
        val post = GhostPost(
            feature_image = "https://example.com/img.jpg",
            feature_image_alt = "A beautiful landscape"
        )
        assertEquals("A beautiful landscape", post.feature_image_alt)
    }

    @Test
    fun `GhostPost serializes feature_image_alt to JSON`() {
        val post = GhostPost(
            title = "Test",
            feature_image = "https://example.com/img.jpg",
            feature_image_alt = "Alt description"
        )
        val json = gson.toJson(post)
        assertTrue(json.contains("\"feature_image_alt\":\"Alt description\""))
    }

    @Test
    fun `GhostPost deserializes feature_image_alt from JSON`() {
        val json = """{"id":"1","feature_image":"https://example.com/img.jpg","feature_image_alt":"Test alt"}"""
        val post = gson.fromJson(json, GhostPost::class.java)
        assertEquals("Test alt", post.feature_image_alt)
    }

    @Test
    fun `GhostPost deserializes with missing feature_image_alt`() {
        val json = """{"id":"1","feature_image":"https://example.com/img.jpg"}"""
        val post = gson.fromJson(json, GhostPost::class.java)
        assertNull(post.feature_image_alt)
    }

    @Test
    fun `FeedPost default imageAlt is null`() {
        val post = FeedPost(
            title = "Test",
            textContent = "Content",
            htmlContent = null,
            imageUrl = null,
            linkUrl = null,
            linkTitle = null,
            linkDescription = null,
            linkImageUrl = null,
            status = "published",
            publishedAt = null,
            createdAt = null,
            updatedAt = null
        )
        assertNull(post.imageAlt)
    }

    @Test
    fun `FeedPost stores imageAlt`() {
        val post = FeedPost(
            title = "Test",
            textContent = "Content",
            htmlContent = null,
            imageUrl = "https://example.com/img.jpg",
            imageAlt = "Image description",
            linkUrl = null,
            linkTitle = null,
            linkDescription = null,
            linkImageUrl = null,
            status = "published",
            publishedAt = null,
            createdAt = null,
            updatedAt = null
        )
        assertEquals("Image description", post.imageAlt)
    }

    @Test
    fun `PostWrapper includes feature_image_alt in serialized JSON`() {
        val wrapper = PostWrapper(listOf(GhostPost(
            title = "Post with alt",
            feature_image = "https://example.com/photo.jpg",
            feature_image_alt = "Photo description"
        )))
        val json = gson.toJson(wrapper)
        assertTrue(json.contains("\"feature_image_alt\":\"Photo description\""))
    }

    // --- email_only field ---

    @Test
    fun `GhostPost default email_only is null`() {
        val post = GhostPost()
        assertNull(post.email_only)
    }

    @Test
    fun `GhostPost stores email_only true`() {
        val post = GhostPost(email_only = true)
        assertEquals(true, post.email_only)
    }

    @Test
    fun `GhostPost serializes email_only to JSON`() {
        val post = GhostPost(title = "Email post", email_only = true)
        val json = gson.toJson(post)
        assertTrue(json.contains("\"email_only\":true"))
    }

    @Test
    fun `GhostPost deserializes email_only from JSON`() {
        val json = """{"id":"1","email_only":true}"""
        val post = gson.fromJson(json, GhostPost::class.java)
        assertEquals(true, post.email_only)
    }

    @Test
    fun `GhostPost deserializes with missing email_only`() {
        val json = """{"id":"1","title":"Test"}"""
        val post = gson.fromJson(json, GhostPost::class.java)
        assertNull(post.email_only)
    }

    // --- FeedPost emailOnly ---

    @Test
    fun `FeedPost default emailOnly is false`() {
        val post = FeedPost(
            title = "Test",
            textContent = "Content",
            htmlContent = null,
            imageUrl = null,
            linkUrl = null,
            linkTitle = null,
            linkDescription = null,
            linkImageUrl = null,
            status = "published",
            publishedAt = null,
            createdAt = null,
            updatedAt = null
        )
        assertFalse(post.emailOnly)
    }

    @Test
    fun `FeedPost stores emailOnly true`() {
        val post = FeedPost(
            title = "Test",
            textContent = "Content",
            htmlContent = null,
            imageUrl = null,
            linkUrl = null,
            linkTitle = null,
            linkDescription = null,
            linkImageUrl = null,
            status = "sent",
            publishedAt = null,
            createdAt = null,
            updatedAt = null,
            emailOnly = true
        )
        assertTrue(post.emailOnly)
    }

    // --- LocalPost emailOnly ---

    @Test
    fun `LocalPost default emailOnly is false`() {
        val post = LocalPost()
        assertFalse(post.emailOnly)
    }

    @Test
    fun `LocalPost stores emailOnly true`() {
        val post = LocalPost(emailOnly = true, newsletterSlug = "default-newsletter")
        assertTrue(post.emailOnly)
        assertEquals("default-newsletter", post.newsletterSlug)
    }
}
