package com.correx.core.validation.artifact

import com.correx.core.artifacts.kind.JsonSchema
import com.correx.core.artifacts.kind.JsonSchemaProperty
import kotlinx.serialization.json.Json
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.Test

class JsonSchemaValidatorTest {

    private val schema = JsonSchema(
        type = "object",
        properties = mapOf(
            "summary" to JsonSchemaProperty(type = "string"),
            "score" to JsonSchemaProperty(type = "integer"),
        ),
        required = listOf("summary", "score"),
        additionalProperties = false,
    )

    private fun errors(json: String) =
        JsonSchemaValidator.validate(schema, Json.parseToJsonElement(json))

    @Test
    fun `valid object passes`() {
        assertTrue(errors("""{"summary":"ok","score":3}""").isEmpty())
    }

    @Test
    fun `missing required property is flagged`() {
        assertTrue(errors("""{"summary":"ok"}""").any { it.contains("score") })
    }

    @Test
    fun `wrong property type is flagged`() {
        assertTrue(errors("""{"summary":"ok","score":"high"}""").any { it.contains("score") && it.contains("integer") })
    }

    @Test
    fun `unknown property is flagged when additionalProperties is false`() {
        assertTrue(errors("""{"summary":"ok","score":3,"extra":1}""").any { it.contains("extra") })
    }

    @Test
    fun `unknown property is allowed when additionalProperties is true`() {
        val open = schema.copy(additionalProperties = true)
        val result = JsonSchemaValidator.validate(
            open,
            Json.parseToJsonElement("""{"summary":"ok","score":3,"extra":1}"""),
        )
        assertTrue(result.isEmpty())
    }

    @Test
    fun `non-object payload against object schema is flagged`() {
        assertEquals(1, errors("""["a","b"]""").size)
    }

    private val arraySchema = JsonSchema(
        type = "object",
        properties = mapOf(
            "tags" to JsonSchemaProperty(type = "array", minItems = 1, items = JsonSchemaProperty(type = "string")),
        ),
        required = listOf("tags"),
        additionalProperties = true,
    )

    private fun arrayErrors(json: String) =
        JsonSchemaValidator.validate(arraySchema, Json.parseToJsonElement(json))

    @Test
    fun `non-empty typed array passes`() {
        assertTrue(arrayErrors("""{"tags":["a","b"]}""").isEmpty())
    }

    @Test
    fun `empty array violates minItems`() {
        assertTrue(arrayErrors("""{"tags":[]}""").any { it.contains("tags") && it.contains("at least 1") })
    }

    @Test
    fun `wrong array element type is flagged with index`() {
        assertTrue(arrayErrors("""{"tags":["ok",3]}""").any { it.contains("tags") && it.contains("[1]") })
    }

    @Test
    fun `non-array value for array property is flagged`() {
        assertTrue(arrayErrors("""{"tags":"nope"}""").any { it.contains("tags") && it.contains("array") })
    }
}
