package com.correx.core.events.serialization

import com.correx.core.events.events.EventPayload
import com.correx.core.events.events.PlanLintCompletedEvent
import com.correx.core.events.events.PlanLintFinding
import com.correx.core.events.types.SessionId
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertTrue

class PlanLintCompletedEventSerializationTest {

    private val sample = PlanLintCompletedEvent(
        sessionId = SessionId("sess-1"),
        candidateId = "freestyle-sess-1",
        hardFailures = listOf(
            PlanLintFinding(
                code = "unproduced_need",
                stageId = "implement",
                detail = "needs 'design', produced by no stage",
            ),
            PlanLintFinding(code = "trap_state", stageId = "loop", detail = "no path to 'done'"),
        ),
        softFindings = listOf(
            PlanLintFinding(code = "fan_out", stageId = "analyze", detail = "5 outgoing edges"),
        ),
        score = 3,
    )

    @Test
    fun `round-trips as polymorphic EventPayload`() {
        val encoded = eventJson.encodeToString(EventPayload.serializer(), sample)
        assertTrue(encoded.contains("\"type\":\"PlanLintCompleted\""), "SerialName must be present: $encoded")
        val decoded = eventJson.decodeFromString(EventPayload.serializer(), encoded)
        assertEquals(sample, decoded)
    }

    @Test
    fun `decodes hand-written PlanLintCompleted JSON`() {
        val json = """
            {"type":"PlanLintCompleted","sessionId":"s","candidateId":"c1",
             "hardFailures":[{"code":"unproduced_need","stageId":"x","detail":"needs y"}],
             "softFindings":[],"score":0}
        """.trimIndent()
        val decoded = eventJson.decodeFromString(EventPayload.serializer(), json)
        assertTrue(decoded is PlanLintCompletedEvent)
        val event = decoded as PlanLintCompletedEvent
        assertEquals("unproduced_need", event.hardFailures.single().code)
        assertEquals("x", event.hardFailures.single().stageId)
        assertTrue(event.softFindings.isEmpty())
    }

    @Test
    fun `plan-level finding allows null stageId`() {
        val withNull = sample.copy(
            hardFailures = listOf(PlanLintFinding(code = "trap_state", stageId = null, detail = "plan-level")),
        )
        val encoded = eventJson.encodeToString(EventPayload.serializer(), withNull)
        val decoded = eventJson.decodeFromString(EventPayload.serializer(), encoded)
        assertEquals(withNull, decoded)
    }
}
