package com.correx.apps.server.memory

import com.correx.core.config.ProjectConfig
import com.correx.core.events.events.EventMetadata
import com.correx.core.events.events.NewEvent
import com.correx.core.events.events.WorkspaceStateObservedEvent
import com.correx.core.events.types.EventId
import com.correx.core.events.types.SessionId
import com.correx.core.inference.Embedder
import com.correx.core.journal.DecisionJournalProjector
import com.correx.core.journal.DefaultDecisionJournalReducer
import com.correx.core.journal.DefaultDecisionJournalRepository
import com.correx.core.talkie.l3.InMemoryL3MemoryStore
import com.correx.core.sessions.projections.replay.DefaultEventReplayer
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.assertTrue
import org.junit.jupiter.api.Test
import java.util.UUID

private class ConstantEmbedder(override val dimension: Int = 8) : Embedder {
    override suspend fun embed(text: String): FloatArray = FloatArray(dimension) { 1f }
}

class ProjectMemoryServiceObservationTest {

    private fun service(
        config: ProjectConfig,
        es: InMemoryEventStore,
        probeResult: WorkspaceState?,
    ) = ProjectMemoryService(
        config = config,
        embedder = ConstantEmbedder(),
        l3MemoryStore = InMemoryL3MemoryStore(),
        journalRepository = DefaultDecisionJournalRepository(
            DefaultEventReplayer(es, DecisionJournalProjector(DefaultDecisionJournalReducer())),
        ),
        eventStore = es,
        workspaceStateProbe = FakeWorkspaceStateProbe(probeResult),
    )

    @Test
    fun `probe success emits WorkspaceStateObservedEvent`(): Unit = runBlocking {
        val es = InMemoryEventStore()
        val config = ProjectConfig(enabled = true)
        val sessionId = SessionId("session-obs-1")

        service(config, es, WorkspaceState("git:abc123", "git", "main", false))
            .observeAndRecord(sessionId, "/repo")

        val events = es.read(sessionId)
            .mapNotNull { it.payload as? WorkspaceStateObservedEvent }
        assertEquals(1, events.size, "expected exactly one WorkspaceStateObservedEvent")
        val evt = events.single()
        assertEquals("git:abc123", evt.stateKey)
        assertEquals("git", evt.source)
        assertEquals("main", evt.branch)
        assertEquals(false, evt.dirty)
    }

    @Test
    fun `probe null emits no event`(): Unit = runBlocking {
        val es = InMemoryEventStore()
        val config = ProjectConfig(enabled = true)
        val sessionId = SessionId("session-obs-2")

        service(config, es, null).observeAndRecord(sessionId, "/repo")

        val events = es.read(sessionId)
            .mapNotNull { it.payload as? WorkspaceStateObservedEvent }
        assertTrue(events.isEmpty(), "expected no events when probe returns null")
    }

    @Test
    fun `disabled config skips observation`(): Unit = runBlocking {
        val es = InMemoryEventStore()
        val config = ProjectConfig(enabled = false)
        val sessionId = SessionId("session-obs-3")

        service(config, es, WorkspaceState("git:abc123", "git", "main", false))
            .observeAndRecord(sessionId, "/repo")

        val events = es.read(sessionId)
            .mapNotNull { it.payload as? WorkspaceStateObservedEvent }
        assertTrue(events.isEmpty(), "expected no events when config is disabled")
    }
}
