package com.correx.core.events

import com.correx.core.approvals.Tier
import com.correx.core.events.events.EventPayload
import com.correx.core.events.events.ToolExecutionCompletedEvent
import com.correx.core.events.events.ToolExecutionFailedEvent
import com.correx.core.events.events.ToolExecutionRejectedEvent
import com.correx.core.events.events.ToolExecutionStartedEvent
import com.correx.core.events.events.ToolInvocationRequestedEvent
import com.correx.core.events.events.ToolReceipt
import com.correx.core.events.events.ToolRequest
import com.correx.core.events.serialization.eventJson
import com.correx.core.events.types.SessionId
import com.correx.core.events.types.StageId
import com.correx.core.events.types.ToolInvocationId
import kotlinx.datetime.Instant
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test

class ToolEventsSerializationTest {
    private val invocationId = ToolInvocationId("inv-1")
    private val sessionId = SessionId("s-1")
    private val stageId = StageId("st-1")

    private val request = ToolRequest(
        invocationId = invocationId,
        sessionId = sessionId,
        stageId = stageId,
        toolName = "echo",
        parameters = mapOf("key" to "value", "count" to 42L)
    )

    private val receipt = ToolReceipt(
        invocationId = invocationId,
        toolName = "echo",
        exitCode = 0,
        outputSummary = "done",
        structuredOutput = mapOf("result" to "ok"),
        affectedEntities = listOf("file.txt"),
        durationMs = 100L,
        tier = Tier.T0,
        timestamp = Instant.parse("2026-01-01T00:00:00Z")
    )

    @Test
    fun `ToolInvocationRequestedEvent round-trips`() {
        val event = ToolInvocationRequestedEvent(invocationId, sessionId, stageId, "echo", Tier.T0, request)
        val json = eventJson.encodeToString(ToolInvocationRequestedEvent.serializer(), event)
        assertEquals(event, eventJson.decodeFromString(ToolInvocationRequestedEvent.serializer(), json))
    }

    @Test
    fun `ToolExecutionStartedEvent round-trips`() {
        val event = ToolExecutionStartedEvent(invocationId, sessionId, "echo")
        val json = eventJson.encodeToString(ToolExecutionStartedEvent.serializer(), event)
        assertEquals(event, eventJson.decodeFromString(ToolExecutionStartedEvent.serializer(), json))
    }

    @Test
    fun `ToolExecutionCompletedEvent round-trips`() {
        val event = ToolExecutionCompletedEvent(invocationId, sessionId, "echo", receipt)
        val json = eventJson.encodeToString(ToolExecutionCompletedEvent.serializer(), event)
        assertEquals(event, eventJson.decodeFromString(ToolExecutionCompletedEvent.serializer(), json))
    }

    @Test
    fun `ToolExecutionFailedEvent round-trips`() {
        val event = ToolExecutionFailedEvent(invocationId, sessionId, "echo", "something broke")
        val json = eventJson.encodeToString(ToolExecutionFailedEvent.serializer(), event)
        assertEquals(event, eventJson.decodeFromString(ToolExecutionFailedEvent.serializer(), json))
    }

    @Test
    fun `ToolExecutionRejectedEvent round-trips`() {
        val event = ToolExecutionRejectedEvent(invocationId, sessionId, "echo", Tier.T4, "tier too high")
        val json = eventJson.encodeToString(ToolExecutionRejectedEvent.serializer(), event)
        assertEquals(event, eventJson.decodeFromString(ToolExecutionRejectedEvent.serializer(), json))
    }

    @Test
    fun `ToolRequest with parameters round-trips`() {
        val json = eventJson.encodeToString(ToolRequest.serializer(), request)
        assertEquals(request, eventJson.decodeFromString(ToolRequest.serializer(), json))
    }

    @Test
    fun `ToolReceipt with structuredOutput round-trips`() {
        val json = eventJson.encodeToString(ToolReceipt.serializer(), receipt)
        assertEquals(receipt, eventJson.decodeFromString(ToolReceipt.serializer(), json))
    }

    @Test
    fun `ToolInvocationRequestedEvent round-trips through polymorphic EventPayload`() {
        val event = ToolInvocationRequestedEvent(invocationId, sessionId, stageId, "echo", Tier.T0, request)
        val json = eventJson.encodeToString(EventPayload.serializer(), event)
        val decoded = eventJson.decodeFromString(EventPayload.serializer(), json)
        assertEquals(event, decoded)
    }
}
