package com.correx.apps.cli.commands

import kotlinx.serialization.json.JsonObject
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.Test

class EventRenderTest {

    private val rows = listOf(
        EventRow(
            sequence = 1L,
            eventId = "e1",
            type = "WorkspaceStateObserved",
            timestamp = "2026-06-12T10:00:00Z",
            causationId = null,
            correlationId = null,
            payload = JsonObject(emptyMap()),
        ),
        EventRow(
            sequence = 2L,
            eventId = "e2",
            type = "InitialIntent",
            timestamp = "2026-06-12T10:01:00Z",
            causationId = "c1",
            correlationId = null,
            payload = JsonObject(emptyMap()),
        ),
    )

    @Test
    fun `renderEventRows includes sequence numbers in order`() {
        val output = renderEventRows(rows)
        val lines = output.lines().filter { it.isNotBlank() }
        // header + 2 data rows
        assertTrue(lines.size >= 3)
        assertTrue(lines[1].trimStart().startsWith("1"))
        assertTrue(lines[2].trimStart().startsWith("2"))
    }

    @Test
    fun `renderEventRows includes type column content`() {
        val output = renderEventRows(rows)
        assertTrue(output.contains("WorkspaceStateObserved"))
        assertTrue(output.contains("InitialIntent"))
    }

    @Test
    fun `renderEventRows shows causation id when present`() {
        val output = renderEventRows(rows)
        assertTrue(output.contains("c1"))
    }

    @Test
    fun `renderEventRows shows dash when causation id absent`() {
        val output = renderEventRows(rows)
        assertTrue(output.contains("-"))
    }

    @Test
    fun `renderEventRows returns no-events message for empty list`() {
        val output = renderEventRows(emptyList())
        assertTrue(output.contains("no events"))
    }

    @Test
    fun `renderDot generates correct node lines for all events`() {
        val testRows = listOf(
            EventRow(
                sequence = 1L,
                eventId = "e1",
                type = "WorkspaceStateObserved",
                timestamp = "2026-06-12T10:00:00Z",
                causationId = null,
                correlationId = null,
                payload = JsonObject(emptyMap()),
            ),
            EventRow(
                sequence = 2L,
                eventId = "e2",
                type = "InitialIntent",
                timestamp = "2026-06-12T10:01:00Z",
                causationId = "e1",
                correlationId = null,
                payload = JsonObject(emptyMap()),
            ),
            EventRow(
                sequence = 3L,
                eventId = "e3",
                type = "SomeEvent",
                timestamp = "2026-06-12T10:02:00Z",
                causationId = null,
                correlationId = null,
                payload = JsonObject(emptyMap()),
            ),
        )
        val output = renderDot(testRows)

        // Check structure
        assertTrue(output.startsWith("digraph session {"), "Output should start with digraph session {")
        assertTrue(output.endsWith("}"), "Output should end with }")

        // Check node lines with labels (eventId and type #sequence)
        assertTrue(output.contains(""""e1" [label="WorkspaceStateObserved #1"]"""), "Should contain e1 node with label")
        assertTrue(output.contains(""""e2" [label="InitialIntent #2"]"""), "Should contain e2 node with label")
        assertTrue(output.contains(""""e3" [label="SomeEvent #3"]"""), "Should contain e3 node with label")

        // Check edge for e2 -> e1 (causation)
        assertTrue(output.contains(""""e2" -> "e1""""), "Should contain edge from e2 to its causation e1")

        // Check that e1 and e3 (with null causation) don't have outgoing edges
        assertTrue(!output.contains(""""e1" -> """"), "e1 should not have outgoing edge (no causation)")
        assertTrue(!output.contains(""""e3" -> """"), "e3 should not have outgoing edge (no causation)")
    }

    @Test
    fun `renderDot returns empty digraph for no events`() {
        val output = renderDot(emptyList())
        assertTrue(output.startsWith("digraph session {"), "Should start with digraph session {")
        assertTrue(output.endsWith("}"), "Should end with }")
    }

    @Test
    fun `renderDot handles events with causationId matching eventId`() {
        val testRows = listOf(
            EventRow(
                sequence = 1L,
                eventId = "e1",
                type = "Event1",
                timestamp = "2026-06-12T10:00:00Z",
                causationId = null,
                correlationId = null,
                payload = JsonObject(emptyMap()),
            ),
            EventRow(
                sequence = 2L,
                eventId = "e2",
                type = "Event2",
                timestamp = "2026-06-12T10:01:00Z",
                causationId = "e1",
                correlationId = null,
                payload = JsonObject(emptyMap()),
            ),
        )
        val output = renderDot(testRows)
        assertTrue(output.contains(""""e2" -> "e1""""), "Should correctly reference causation by ID")
    }
}
