package com.correx.apps.server.git

import com.correx.core.config.GitConfig
import com.correx.core.events.events.RunBranchPushedEvent
import com.correx.core.events.types.SessionId
import com.correx.infrastructure.persistence.InMemoryEventStore
import kotlinx.coroutines.runBlocking
import org.junit.jupiter.api.Test
import java.nio.file.Files
import java.nio.file.Path
import java.util.concurrent.TimeUnit
import kotlin.io.path.writeText
import kotlin.test.assertEquals
import kotlin.test.assertTrue

class GitRunBranchTransportTest {

    @Test
    fun `creates a run branch, pushes it, and records the pushed ref`(): Unit = runBlocking {
        val root = Files.createTempDirectory("correx-git-transport")
        val remote = Files.createTempDirectory("correx-git-remote")
        git(root, "init", "-b", "main")
        git(root, "config", "user.name", "Test User")
        git(root, "config", "user.email", "test@example.test")
        root.resolve("README.md").writeText("base\n")
        git(root, "add", "README.md")
        git(root, "commit", "-m", "base")
        git(remote, "init", "--bare")
        git(root, "remote", "add", "origin", remote.toString())
        git(root, "push", "origin", "main")

        val store = InMemoryEventStore()
        val sessionId = SessionId("git-transport")
        val transport = GitRunBranchTransport(
            store,
            GitConfig(enabled = true, remote = "origin", baseBranch = "main"),
        )

        transport.onRunBranch(sessionId, root) {
            root.resolve("agent-output.txt").writeText("generated\n")
        }

        assertEquals("run/git-transport", git(root, "branch", "--show-current").trim())
        assertTrue(git(root, "ls-remote", "--heads", "origin", "run/git-transport").isNotBlank())
        val pushed = store.read(sessionId).single().payload as RunBranchPushedEvent
        assertEquals("run/git-transport", pushed.branch)
        assertTrue(pushed.baseSha.isNotBlank())
        assertEquals(git(root, "rev-parse", "HEAD").trim(), pushed.headSha)
    }

    private fun git(root: Path, vararg args: String): String {
        val process = ProcessBuilder(listOf("git", "-C", root.toString()) + args)
            .redirectErrorStream(true)
            .start()
        val output = process.inputStream.bufferedReader().use { it.readText() }
        check(process.waitFor(20, TimeUnit.SECONDS)) { "git ${args.joinToString(" ")} timed out" }
        check(process.exitValue() == 0) { "git ${args.joinToString(" ")} failed: $output" }
        return output
    }
}
