package com.correx.infrastructure.workflow

import com.correx.core.artifacts.kind.ConfigArtifactKind
import com.correx.core.artifacts.kind.DefaultArtifactKindRegistry
import com.correx.core.artifacts.kind.JsonSchema
import com.correx.core.artifacts.kind.JsonSchemaProperty
import com.correx.core.events.types.StageId
import com.correx.core.transitions.conditions.ArtifactFieldEquals
import com.correx.core.transitions.conditions.FieldOperator
import org.junit.jupiter.api.Assumptions.assumeTrue
import org.junit.jupiter.api.Test
import java.nio.file.Path
import kotlin.io.path.exists
import kotlin.test.assertEquals
import kotlin.test.assertTrue

class RolePipelineWorkflowTest {

    private fun llmKind(id: String) = ConfigArtifactKind(
        id = id,
        schema = JsonSchema(
            type = "object",
            properties = mapOf("verdict" to JsonSchemaProperty(type = "string")),
            additionalProperties = true,
        ),
        llmEmitted = true,
    )

    private val registry = DefaultArtifactKindRegistry().apply {
        register(llmKind("analysis"))
        register(llmKind("design"))
        register(llmKind("impl_plan"))
        register(llmKind("review_report"))
    }

    // Walk up from the working dir to the repo root so the test finds the shipped file
    // regardless of which module dir Gradle runs it from.
    private fun repoFile(rel: String): Path? {
        var dir: Path? = Path.of(System.getProperty("user.dir")).toAbsolutePath()
        while (dir != null) {
            val candidate = dir.resolve(rel)
            if (candidate.exists()) return candidate
            dir = dir.parent
        }
        return null
    }

    @Test
    fun `shipped role_pipeline toml parses with the full role graph`() {
        val path = repoFile("examples/workflows/role_pipeline.toml")
        assumeTrue(path != null, "role_pipeline.toml not found from ${System.getProperty("user.dir")}")

        val graph = TomlWorkflowLoader(registry).load(path!!)

        assertEquals(
            setOf("analyst", "architect", "planner", "implementer", "reviewer"),
            graph.stages.keys.map { it.value }.toSet(),
        )
        assertEquals(6, graph.transitions.size)

        // Forward chaining via needs.
        assertTrue(graph.stages[StageId("reviewer")]!!.needs.map { it.value }.containsAll(listOf("patch", "impl_plan")))

        // Verdict-gated loop: approved → done, changes → implementer.
        val approved = graph.transitions.first { it.to == StageId("done") }.condition as ArtifactFieldEquals
        assertEquals(FieldOperator.EQ, approved.operator)
        assertEquals("verdict", approved.field)
        val loop = graph.transitions
            .first { it.from == StageId("reviewer") && it.to == StageId("implementer") }
            .condition as ArtifactFieldEquals
        assertEquals(FieldOperator.NEQ, loop.operator)
    }
}
