/*
 * SPDX-License-Identifier: GPL-3.0-or-later
 */
package com.runicgateway.app.data.api.dto

import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.jsonPrimitive
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNull
import org.junit.Assert.assertTrue
import org.junit.Test

/**
 * Decode tests for the news post + CMS page + contact DTOs (`/public/posts…`,
 * `/public/pages/:slug`, `/public/contact`). One [PostDto] shape serves both the
 * list (no body) and detail (with body); a [PageDto] keeps block props as raw JSON.
 */
class ContentDtoTest {

    private val json = Json {
        ignoreUnknownKeys = true
        explicitNulls = false
        coerceInputValues = true
    }

    @Test fun postDetailDecodesBodyAndImage() {
        val dto = json.decodeFromString<PostDto>(
            """{"id":10,"category":"news","title":"Update","slug":"update",
                "excerpt":"e","body":"<p>full</p>","image_url":"/i.png",
                "published_at":"2026-07-21T00:00:00Z","created_at":"2026-07-20T00:00:00Z"}""",
        )
        assertEquals(10L, dto.id)
        assertEquals("<p>full</p>", dto.body)
        assertEquals("/i.png", dto.imageUrl)
        assertEquals("2026-07-21T00:00:00Z", dto.publishedAt)
    }

    @Test fun postListRowToleratesMissingBody() {
        val dto = json.decodeFromString<PostDto>("""{"id":11,"category":"newsletter","title":"N"}""")
        assertNull(dto.body)
        assertNull(dto.imageUrl)
    }

    @Test fun pageDecodesBlocksWithRawProps() {
        val dto = json.decodeFromString<PageDto>(
            """{
                "id":3,"slug":"about","title":"About","status":"published",
                "blocks":[
                    {"type":"heading","props":{"text":"Welcome","level":1},"visible":true},
                    {"type":"divider","props":{}}
                ],
                "publishedAt":"2026-07-01T00:00:00Z"
            }""",
        )
        assertEquals("about", dto.slug)
        assertEquals(2, dto.blocks.size)
        assertEquals("heading", dto.blocks[0].type)
        // props stay a raw JSON object the renderer reads by key.
        assertEquals("Welcome", dto.blocks[0].props["text"]!!.jsonPrimitive.content)
        assertTrue(dto.blocks[1].visible) // default true when absent
    }

    @Test fun contactResponseSentAndFallbackVariants() {
        val sent = json.decodeFromString<ContactResponse>("""{"sent":true}""")
        assertTrue(sent.sent)
        assertNull(sent.fallback)

        val fallback = json.decodeFromString<ContactResponse>(
            """{"sent":false,"fallback":"mailto","email":"a@b.c"}""",
        )
        assertEquals("mailto", fallback.fallback)
        assertEquals("a@b.c", fallback.email)
    }

    @Test fun contactRequestEncodesAllFields() {
        val body = json.encodeToString(ContactRequest(name = "Gwen", email = "g@x.c", message = "hi"))
        assertTrue(body.contains("\"name\":\"Gwen\""))
        assertTrue(body.contains("\"email\":\"g@x.c\""))
        assertTrue(body.contains("\"message\":\"hi\""))
    }
}
