package com.correx.apps.server.tasks

import com.correx.core.artifactstore.ArtifactStore
import com.correx.core.events.events.ArtifactContentStoredEvent
import com.correx.core.events.events.ArtifactCreatedEvent
import com.correx.core.events.events.EventMetadata
import com.correx.core.events.events.InitialIntentEvent
import com.correx.core.events.events.NewEvent
import com.correx.core.events.events.WorkflowCompletedEvent
import com.correx.core.events.events.WorkflowStartedEvent
import com.correx.core.events.stores.EventStore
import com.correx.core.events.types.ArtifactId
import com.correx.core.events.types.EventId
import com.correx.core.events.types.SessionId
import com.correx.core.events.types.StageId
import com.correx.infrastructure.persistence.InMemoryEventStore
import kotlinx.coroutines.runBlocking
import kotlinx.datetime.Clock
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertNull
import org.junit.jupiter.api.Test
import java.util.UUID

class TaskLinkResolverTest {

    private val store: EventStore = InMemoryEventStore()

    private suspend fun append(sessionId: SessionId, payload: com.correx.core.events.events.EventPayload) {
        store.append(
            NewEvent(
                metadata = EventMetadata(
                    eventId = EventId(UUID.randomUUID().toString()),
                    sessionId = sessionId,
                    timestamp = Clock.System.now(),
                    schemaVersion = 1,
                    causationId = null,
                    correlationId = null,
                ),
                payload = payload,
            ),
        )
    }

    @Test
    fun `session resolver projects status and intent and is null for an unknown id`() = runBlocking {
        val sessionId = SessionId("sess-9")
        append(sessionId, InitialIntentEvent(sessionId, "build auth"))
        append(sessionId, WorkflowStartedEvent(sessionId, "role_pipeline", StageId("architect")))
        append(sessionId, WorkflowCompletedEvent(sessionId, StageId("review"), totalStages = 3))

        val resolver = SessionSummaryTaskSessionResolver(store)
        val resolved = resolver.resolve("sess-9")!!

        assertEquals("COMPLETED", resolved.status)
        assertEquals("build auth", resolved.intent)
        assertEquals("role_pipeline", resolved.workflowId)
        assertNull(resolver.resolve("sess-unknown"))
    }

    @Test
    fun `artifact resolver reads stage, session and content excerpt and is null for an unknown id`() = runBlocking {
        val sessionId = SessionId("sess-9")
        val artifactId = ArtifactId("art-1")
        val contentHash = ArtifactId("hash-1")
        val artifactStore = FakeArtifactStore(mapOf(contentHash to "approach: use redis".toByteArray()))
        append(sessionId, ArtifactContentStoredEvent(artifactId, contentHash, sessionId, StageId("architect")))
        append(sessionId, ArtifactCreatedEvent(artifactId, sessionId, StageId("architect"), schemaVersion = 1))

        val resolver = EventStoreTaskArtifactResolver(store, artifactStore)
        val resolved = resolver.resolve("art-1")!!

        assertEquals("architect", resolved.stage)
        assertEquals("sess-9", resolved.sessionId)
        assertEquals("approach: use redis", resolved.excerpt)
        assertNull(resolver.resolve("art-unknown"))
    }

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