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 org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.Test
import java.nio.file.Path
import kotlin.io.path.exists

/**
 * Validates that the shipped research workflow (examples/workflows/research.toml) parses into a
 * structurally valid WorkflowGraph: reachable stages, every `needs` produced upstream, the gather
 * stage wired to the two network tools. Synthesis quality is inference-dependent and out of scope;
 * this guards the graph contract.
 */
class ResearchWorkflowTest {

    private val registry = DefaultArtifactKindRegistry().apply {
        listOf("research_plan", "source_dossier", "research_report").forEach { id ->
            register(ConfigArtifactKind(id = id, schema = JsonSchema(type = "object"), llmEmitted = true))
        }
    }

    private fun repoFile(relative: String): Path {
        var dir: Path? = Path.of("").toAbsolutePath()
        while (dir != null) {
            val candidate = dir.resolve(relative)
            if (candidate.exists()) return candidate
            dir = dir.parent
        }
        error("could not locate $relative from ${Path.of("").toAbsolutePath()}")
    }

    @Test
    fun `research workflow builds a valid graph`() {
        val graph = TomlWorkflowLoader(registry).load(repoFile("examples/workflows/research.toml"))

        assertEquals("research", graph.id)
        assertEquals("decompose", graph.start.value)
        assertEquals(setOf("decompose", "gather", "report"), graph.stages.keys.map { it.value }.toSet())

        val gather = graph.stages.values.first { it.produces.any { a -> a.name.value == "source_dossier" } }
        assertEquals(setOf("research_plan"), gather.needs.map { it.value }.toSet())
        assertEquals(setOf("web_search", "web_fetch"), gather.allowedTools)

        val report = graph.stages.values.first { it.produces.any { a -> a.name.value == "research_report" } }
        assertEquals(setOf("source_dossier"), report.needs.map { it.value }.toSet())

        assertTrue(graph.transitions.any { it.to.value == "done" }, "must terminate at done")
    }
}
