package com.correx.core.kernel.orchestration

import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertFalse
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.Test

class BriefEchoDiffTest {

    // --- helpers ---

    private fun brief(vararg requirements: String, files: List<String> = emptyList()): String {
        val reqs = requirements.joinToString(",") { "\"$it\"" }
        val fileArr = files.joinToString(",") { "\"$it\"" }
        return """{"summary":"do the thing","requirements":[$reqs],"affected_areas":[$fileArr]}"""
    }

    private fun echo(
        vararg criteria: String,
        files: List<String> = emptyList(),
        symbols: List<String> = emptyList(),
    ): String {
        val crit = criteria.joinToString(",") { "\"$it\"" }
        val fileArr = files.joinToString(",") { "\"$it\"" }
        val symArr = symbols.joinToString(",") { "\"$it\"" }
        return """{"goal":"do the thing","referenced_files":[$fileArr],""" +
            """"referenced_symbols":[$symArr],"acceptance_criteria":[$crit]}"""
    }

    // --- faithful echo → no mismatch ---

    @Test
    fun `faithful echo produces no mismatch`() {
        val b = brief("the system must retry on transient failures", "all retry attempts must be logged")
        val e = echo("the system must retry on transient failures", "all retry attempts must be logged")
        val div = BriefEchoDiff.compare(b, e)
        assertFalse(div.isMismatch)
        assertTrue(div.uncoveredRequirements.isEmpty())
        assertTrue(div.hallucinatedFiles.isEmpty())
    }

    // --- dropped requirement → uncovered ---

    @Test
    fun `dropped requirement is reported as uncovered`() {
        val b = brief("must emit an event", "must support retries")
        val e = echo("must emit an event")
        val div = BriefEchoDiff.compare(b, e)
        assertTrue(div.isMismatch)
        assertTrue(div.uncoveredRequirements.any { it.contains("retries") })
    }

    @Test
    fun `all requirements dropped marks all as uncovered`() {
        val b = brief("req alpha", "req beta")
        val e = echo() // no criteria
        val div = BriefEchoDiff.compare(b, e)
        assertTrue(div.isMismatch)
        assertEquals(2, div.uncoveredRequirements.size)
    }

    // --- slightly paraphrased but high-overlap requirement → covered ---

    @Test
    fun `near-verbatim paraphrase with high token overlap is covered`() {
        val b = brief("the gate must emit a BriefEchoMismatchEvent on divergence")
        val e = echo("gate must emit BriefEchoMismatchEvent on divergence")
        val div = BriefEchoDiff.compare(b, e)
        assertFalse(div.isMismatch, "High-overlap paraphrase should be covered: ${div.uncoveredRequirements}")
    }

    // --- hallucinated file ---

    @Test
    fun `file not in brief is hallucinated`() {
        val b = brief("do something", files = listOf("core/kernel/Foo.kt"))
        val e = echo("do something", files = listOf("core/ghost/Phantom.kt"))
        val div = BriefEchoDiff.compare(b, e)
        assertTrue(div.hallucinatedFiles.contains("core/ghost/Phantom.kt"))
        assertTrue(div.isMismatch)
    }

    @Test
    fun `file present in brief is not hallucinated`() {
        val b = brief("do something", files = listOf("core/kernel/Foo.kt"))
        val e = echo("do something", files = listOf("core/kernel/Foo.kt"))
        val div = BriefEchoDiff.compare(b, e)
        assertFalse(div.hallucinatedFiles.contains("core/kernel/Foo.kt"))
        assertFalse(div.isMismatch)
    }

    // --- symbol divergence → recorded but isMismatch=false ---

    @Test
    fun `hallucinated symbol is recorded but does not cause isMismatch`() {
        val b = brief("implement the interface")
        val e = echo("implement the interface", symbols = listOf("GhostService"))
        val div = BriefEchoDiff.compare(b, e)
        // Symbol not in brief → hallucinated
        assertTrue(div.hallucinatedSymbols.contains("GhostService"))
        // But isMismatch should be false (symbols are display-only in v1)
        assertFalse(div.isMismatch, "Symbol-only divergence must not block in v1")
    }

    @Test
    fun `symbol present in brief is not hallucinated`() {
        val b = brief("implement SessionOrchestrator interface")
        val e = echo("implement SessionOrchestrator interface", symbols = listOf("SessionOrchestrator"))
        val div = BriefEchoDiff.compare(b, e)
        assertFalse(div.hallucinatedSymbols.contains("SessionOrchestrator"))
    }

    // --- malformed / empty echo → total mismatch ---

    @Test
    fun `malformed echo is treated as total mismatch`() {
        val b = brief("req A", "req B")
        val div = BriefEchoDiff.compare(b, "not valid json at all")
        assertTrue(div.isMismatch)
        assertEquals(2, div.uncoveredRequirements.size)
    }

    @Test
    fun `empty echo JSON object is total mismatch`() {
        val b = brief("req A")
        val div = BriefEchoDiff.compare(b, "{}")
        assertTrue(div.isMismatch)
        assertTrue(div.uncoveredRequirements.isNotEmpty())
    }

    // --- fenced JSON is tolerated ---

    @Test
    fun `fenced echo JSON is tolerated`() {
        val b = brief("must support retries")
        val fenced = "```json\n${echo("must support retries")}\n```"
        val div = BriefEchoDiff.compare(b, fenced)
        assertFalse(div.isMismatch, "Fenced echo should parse and match: ${div.uncoveredRequirements}")
    }

    // --- no requirements in brief → no mismatch ---

    @Test
    fun `brief with no requirements yields no mismatch`() {
        val b = """{"summary":"something","requirements":[]}"""
        val e = echo()
        val div = BriefEchoDiff.compare(b, e)
        assertFalse(div.isMismatch)
        assertTrue(div.uncoveredRequirements.isEmpty())
    }

    // --- tokenize ---

    @Test
    fun `tokenize lowercases and strips punctuation`() {
        val tokens = BriefEchoDiff.tokenize("Must EMIT a BriefEchoMismatchEvent!")
        assertTrue(tokens.contains("must"))
        assertTrue(tokens.contains("emit"))
        assertTrue(tokens.contains("briefechomismatchevent"))
        assertFalse(tokens.contains("a")) // length < 2
    }
}
