import com.correx.core.context.builder.DefaultContextPackBuilder
import com.correx.core.context.compression.DefaultContextCompressor
import com.correx.core.context.model.ContextEntry
import com.correx.core.context.model.ContextLayer
import com.correx.core.context.model.ContextPack
import com.correx.core.context.model.EntryRole
import com.correx.core.context.model.TokenBudget
import com.correx.core.events.types.ContextEntryId
import com.correx.core.events.types.ContextPackId
import com.correx.core.events.types.SessionId
import com.correx.core.events.types.StageId
import com.correx.core.inference.PromptRenderer
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test

class PromptRendererOrderingTest {

    private val sessionId = SessionId("s1")
    private val stageId = StageId("stage-1")

    private fun entry(id: String, layer: ContextLayer, role: EntryRole, sourceType: String) = ContextEntry(
        id = ContextEntryId(id),
        layer = layer,
        content = id,
        sourceType = sourceType,
        sourceId = id,
        tokenEstimate = 10,
        role = role,
    )

    @Test
    fun `stage tool loop renders chronologically with the task before tool turns`() {
        // The builder stamps ordinals from input order; the renderer must honour them so the
        // model sees: system, task, assistant call, tool result, assistant call, tool result.
        val builder = DefaultContextPackBuilder(DefaultContextCompressor())
        val entries = listOf(
            entry("sys", ContextLayer.L0, EntryRole.SYSTEM, "systemPrompt"),
            entry("task", ContextLayer.L1, EntryRole.USER, "agentPrompt"),
            entry("call1", ContextLayer.L2, EntryRole.ASSISTANT, "assistantToolCall"),
            entry("result1", ContextLayer.L2, EntryRole.TOOL, "toolResult"),
            entry("call2", ContextLayer.L2, EntryRole.ASSISTANT, "assistantToolCall"),
            entry("result2", ContextLayer.L2, EntryRole.TOOL, "toolResult"),
        )
        val pack = builder.build(ContextPackId("p"), sessionId, stageId, entries, TokenBudget(limit = 4000))

        val messages = PromptRenderer.render(pack)
        assertEquals(
            listOf("system" to "sys", "user" to "task", "assistant" to "call1",
                "tool" to "result1", "assistant" to "call2", "tool" to "result2"),
            messages.map { it.role to it.content },
        )
    }

    @Test
    fun `without ordinals the live user turn still renders last (router chat fallback)`() {
        // Packs built outside DefaultContextPackBuilder (router chat) leave ordinal at 0;
        // the renderer falls back to layer priority so L1 (the user query) lands last.
        val pack = ContextPack(
            id = ContextPackId("p"),
            sessionId = sessionId,
            stageId = stageId,
            layers = mapOf(
                ContextLayer.L1 to listOf(entry("question", ContextLayer.L1, EntryRole.USER, "chat")),
                ContextLayer.L2 to listOf(entry("memory", ContextLayer.L2, EntryRole.SYSTEM, "l2")),
            ),
            budgetUsed = 20,
            budgetLimit = 4000,
        )
        val messages = PromptRenderer.render(pack)
        assertEquals(listOf("memory", "question"), messages.map { it.content })
    }
}
