package com.correx.core.config

import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertFalse
import org.junit.jupiter.api.Assertions.assertSame
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.io.TempDir
import java.nio.file.Path

class ProjectProfileWriterTest {

    @TempDir
    lateinit var tempDir: Path

    @Test
    fun `write then load round-trips about conventions and commands including embedded quotes`() {
        val profile = ProjectProfile(
            about = "Event-sourced kernel \"the\" orchestrator, Kotlin/JVM 21",
            conventions = listOf(
                "no bare try-catch",
                "prefer the \"narrow\" interface", // a convention with a double-quote
            ),
            commands = mapOf(
                "build" to "./gradlew build",
                "test" to "./gradlew check",
                "node.build" to "npm --prefix frontend run build",
            ),
        )

        ProjectProfileWriter.write(tempDir.toString(), profile)
        val loaded = ProjectProfileLoader.load(tempDir.toString())

        assertEquals(profile.about, loaded.about)
        assertEquals(profile.conventions, loaded.conventions)
        assertEquals(profile.commands, loaded.commands)
        assertEquals(profile, loaded)
    }

    @Test
    fun `writer serializes scoped commands as TOML subtables`() {
        val serialized = ProjectProfileWriter.serialize(
            ProjectProfile(commands = mapOf("node.build" to "npm run build")),
        )

        assertTrue(serialized.contains("[commands.node]"))
        assertTrue(serialized.contains("build = \"npm run build\""))
    }

    @Test
    fun `an empty profile serializes to an empty string and skips empty sections`() {
        val serialized = ProjectProfileWriter.serialize(ProjectProfile())
        assertEquals("", serialized)
        assertFalse(serialized.contains("[commands]"))
    }

    @Test
    fun `blank about is omitted but conventions and commands are still written`() {
        val serialized = ProjectProfileWriter.serialize(
            ProjectProfile(
                about = "   ",
                conventions = listOf("c1"),
                commands = mapOf("run" to "x"),
            ),
        )
        assertFalse(serialized.contains("about ="), "blank about must be skipped")
        assertTrue(serialized.contains("conventions = [\"c1\"]"))
        assertTrue(serialized.contains("[commands]"))
    }

    @Test
    fun `withConvention appends a new convention`() {
        val updated = ProjectProfile(conventions = listOf("a")).withConvention("b")
        assertEquals(listOf("a", "b"), updated.conventions)
    }

    @Test
    fun `withConvention de-dupes an exact existing convention`() {
        val profile = ProjectProfile(conventions = listOf("no bare try-catch"))
        val updated = profile.withConvention("no bare try-catch")
        assertSame(profile, updated, "an exact duplicate must return the same profile unchanged")
        assertEquals(listOf("no bare try-catch"), updated.conventions)
    }

    @Test
    fun `withConvention ignores blank text`() {
        val profile = ProjectProfile(conventions = listOf("a"))
        assertSame(profile, profile.withConvention("   "))
    }
}
