package com.correx.infrastructure.tools

import com.correx.core.artifactstore.ArtifactStore
import com.correx.core.events.events.ToolRequest
import com.correx.core.events.types.ArtifactId
import com.correx.core.events.types.SessionId
import com.correx.core.events.types.StageId
import com.correx.core.events.types.ToolInvocationId
import com.correx.core.tools.contract.ToolResult
import kotlinx.coroutines.runBlocking
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.Test
import java.util.*

class ToolOutputToolTest {

    private class FakeStore(private val entries: Map<String, ByteArray>) : ArtifactStore {
        override suspend fun put(bytes: ByteArray): ArtifactId = error("unused")
        override suspend fun get(id: ArtifactId): ByteArray? = entries[id.value]
        override suspend fun flushBefore(commit: suspend () -> Unit) = commit()
    }

    private fun request(ref: String?) = ToolRequest(
        invocationId = ToolInvocationId(UUID.randomUUID().toString()),
        sessionId = SessionId(UUID.randomUUID().toString()),
        stageId = StageId(UUID.randomUUID().toString()),
        toolName = "tool_output",
        parameters = ref?.let { mapOf("ref" to it) } ?: emptyMap(),
    )

    @Test
    fun `returns the full stored output for a known ref`(): Unit = runBlocking {
        val tool = ToolOutputTool(FakeStore(mapOf("hash1" to "the full output".toByteArray())))
        val out = (tool.execute(request("hash1")) as ToolResult.Success).output
        assertEquals("the full output", out)
    }

    @Test
    fun `unknown ref fails recoverably`(): Unit = runBlocking {
        val tool = ToolOutputTool(FakeStore(emptyMap()))
        val result = tool.execute(request("missing"))
        assertTrue(result is ToolResult.Failure && result.recoverable, result.toString())
    }

    @Test
    fun `missing ref fails recoverably`(): Unit = runBlocking {
        val tool = ToolOutputTool(FakeStore(emptyMap()))
        val result = tool.execute(request(null))
        assertTrue(result is ToolResult.Failure && result.recoverable, result.toString())
    }
}
