package com.correx.infrastructure.persistence

import com.correx.core.events.types.EventId
import com.correx.core.events.types.SessionId
import com.correx.testing.contracts.fixtures.artifactstore.NoopArtifactStore
import com.correx.testing.fixtures.EventFixtures
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
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 org.junit.jupiter.api.io.TempDir
import java.nio.file.Path
import java.sql.DriverManager

class SqliteEventStoreConcurrencyTest {

    @Test
    fun `concurrent appends to same session produce no dropped or duplicate sequence numbers`(
        @TempDir tempDir: Path,
    ): Unit = runBlocking {
        val dbFile = tempDir.resolve("events.db").toAbsolutePath().toString()
        val conn = DriverManager.getConnection("jdbc:sqlite:$dbFile")
        val store = SqliteEventStore(conn, artifactStore = NoopArtifactStore())

        val sessionId = SessionId("concurrent-session")
        val n = 50

        (1..n)
            .map { i ->
                async(Dispatchers.IO) {
                    store.append(EventFixtures.newEvent(EventId("e-$i"), sessionId))
                }
            }
            .awaitAll()

        val events = store.read(sessionId)

        assertEquals(n, events.size, "Expected exactly $n events but got ${events.size}")

        val sessionSeqs = events.map { it.sessionSequence }.sorted()
        assertEquals(
            (1L..n.toLong()).toList(),
            sessionSeqs,
            "Session sequences must be exactly 1..$n with no gaps or duplicates",
        )

        val globalSeqs = events.map { it.sequence }
        assertEquals(globalSeqs.size, globalSeqs.toSet().size, "Global sequence values must all be unique")

        globalSeqs.forEach { seq ->
            assertTrue(seq >= 1L, "Global sequence $seq must be >= 1")
        }
    }
}
