package top.r394realms.ltdmanagertest.util

import org.junit.jupiter.api.*
import org.junit.jupiter.api.Assertions.*
import top.r3944realms.ltdmanager.utils.SqlTemplate
import java.io.File

class SqlTemplateTest {

    companion object {
        private val testDir = File("config/sql/test")

        @BeforeAll
        @JvmStatic
        fun setupFiles() {
            testDir.mkdirs()
            File(testDir, "query_test.sql").writeText("""
                SELECT id, name, status
                FROM test.players
                WHERE id IN (${'$'}{placeholders})
            """.trimIndent())
            File(testDir, "upsert_test.sql").writeText("""
                INSERT INTO test.records (id, value)
                VALUES ${'$'}{values}
                ON DUPLICATE KEY UPDATE value = VALUES(value)
            """.trimIndent())
        }

        @AfterAll
        @JvmStatic
        fun cleanupFiles() {
            testDir.listFiles()?.forEach { it.delete() }
            testDir.delete()
        }
    }

    @BeforeEach
    fun clearCache() {
        SqlTemplate.clearCache()
    }

    @Test
    fun `load template from file and bind single placeholder`() {
        val tmpl = SqlTemplate.fromFile("test/query_test.sql")
        val result = tmpl.bind("placeholders" to "?, ?, ?")

        assertTrue(result.contains("WHERE id IN (?, ?, ?)"))
        assertTrue(result.contains("FROM test.players"))
    }

    @Test
    fun `bind multiple placeholders`() {
        val tmpl = SqlTemplate.fromFile("test/upsert_test.sql")
        val result = tmpl.bind("values" to "(1, 'a'), (2, 'b')")

        assertTrue(result.contains("VALUES (1, 'a'), (2, 'b')"))
        assertTrue(result.contains("ON DUPLICATE KEY UPDATE"))
    }

    @Test
    fun `placeholder not in template leaves result unchanged`() {
        val tmpl = SqlTemplate.fromFile("test/query_test.sql")
        val result = tmpl.bind("nonexistent" to "ignored")

        assertTrue(result.contains("\${placeholders}"))
    }

    @Test
    fun `same path returns cached instance`() {
        val a = SqlTemplate.fromFile("test/query_test.sql")
        val b = SqlTemplate.fromFile("test/query_test.sql")

        assertSame(a, b)
    }

    @Test
    fun `different paths return different instances`() {
        val a = SqlTemplate.fromFile("test/query_test.sql")
        val b = SqlTemplate.fromFile("test/upsert_test.sql")

        assertNotSame(a, b)
    }

    @Test
    fun `loading nonexistent file throws`() {
        assertThrows(IllegalArgumentException::class.java) {
            SqlTemplate.fromFile("nonexistent/file.sql")
        }
    }

    @Test
    fun `bind returns different strings for different bindings`() {
        val tmpl = SqlTemplate.fromFile("test/query_test.sql")
        val r1 = tmpl.bind("placeholders" to "?")
        val r2 = tmpl.bind("placeholders" to "?, ?")

        assertNotEquals(r1, r2)
    }

    @Test
    fun `clearCache evicts all entries`() {
        val a = SqlTemplate.fromFile("test/query_test.sql")
        SqlTemplate.clearCache()
        val b = SqlTemplate.fromFile("test/query_test.sql")

        assertNotSame(a, b)
    }
}
