package kotlinx.schema.generator.json

import io.kotest.assertions.json.shouldEqualJson
import kotlinx.schema.Description
import kotlinx.schema.generator.core.SchemaGeneratorService
import kotlinx.schema.json.JsonSchema
import kotlinx.serialization.json.Json
import org.junitpioneer.jupiter.Issue
import kotlin.reflect.KClass
import kotlin.test.Test

/**
 * Tests for handling name collisions in sealed class hierarchies.
 *
 * When multiple sealed classes have inner classes with the same name (e.g., "Unknown"),
 * the generated JSON Schema definitions must use qualified names like "ParentClass.ChildClass"
 * to avoid collisions in the $defs section.
 */
@Issue("https://github.com/Kotlin/kotlinx-schema/issues/113")
class SealedClassNameCollisionTest {
    @Description("Result type A")
    @Suppress("unused")
    sealed class ResultA {
        @Description("Success result for A")
        data class Success(
            val value: String,
        ) : ResultA()

        @Description("Unknown error for A")
        data class Unknown(
            val code: Int,
        ) : ResultA()
    }

    @Description("Result type B")
    @Suppress("unused")
    sealed class ResultB {
        @Description("Success result for B")
        data class Success(
            val data: Int,
        ) : ResultB()

        @Description("Unknown error for B")
        data class Unknown(
            val message: String,
        ) : ResultB()
    }

    @Description("Container with both result types")
    data class ApiResponse(
        val resultA: ResultA,
        val resultB: ResultB,
    )

    private val generator =
        requireNotNull(
            SchemaGeneratorService.getGenerator(KClass::class, JsonSchema::class),
        ) {
            "ReflectionClassJsonSchemaGenerator must be registered"
        }

    private val json =
        Json {
            prettyPrint = true
            encodeDefaults = false
        }

    @Test
    @Suppress("LongMethod")
    fun `Should use qualified names to avoid name collisions in sealed hierarchies`() {
        // When - generate schema for ApiResponse which uses two sealed hierarchies
        //        where both have "Success" and "Unknown" inner classes
        val schema = generator.generateSchema(ApiResponse::class)

        // Then - all 4 definitions should be present with qualified names
        //       (not 2 due to collision: "Success" and "Unknown")
        json.encodeToString(schema) shouldEqualJson
            $$"""
            {
              "$schema": "https://json-schema.org/draft/2020-12/schema",
              "$id": "kotlinx.schema.generator.json.SealedClassNameCollisionTest.ApiResponse",
              "description": "Container with both result types",
              "type": "object",
              "properties": {
                "resultA": {
                  "$ref": "#/$defs/kotlinx.schema.generator.json.SealedClassNameCollisionTest.ResultA"
                },
                "resultB": {
                  "$ref": "#/$defs/kotlinx.schema.generator.json.SealedClassNameCollisionTest.ResultB"
                }
              },
              "additionalProperties": false,
              "required": [
                "resultA",
                "resultB"
              ],
              "$defs": {
                "kotlinx.schema.generator.json.SealedClassNameCollisionTest.ResultA": {
                  "oneOf": [
                    { "$ref": "#/$defs/kotlinx.schema.generator.json.SealedClassNameCollisionTest.ResultA.Success" },
                    { "$ref": "#/$defs/kotlinx.schema.generator.json.SealedClassNameCollisionTest.ResultA.Unknown" }
                  ],
                  "description": "Result type A"
                },
                "kotlinx.schema.generator.json.SealedClassNameCollisionTest.ResultA.Success": {
                  "type": "object",
                  "description": "Success result for A",
                  "properties": {
                    "type": { 
                      "type": "string", 
                       "const": "kotlinx.schema.generator.json.SealedClassNameCollisionTest.ResultA.Success"
                    },
                    "value": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "type",
                    "value"
                  ],
                  "additionalProperties": false
                },
                "kotlinx.schema.generator.json.SealedClassNameCollisionTest.ResultA.Unknown": {
                  "type": "object",
                  "description": "Unknown error for A",
                  "properties": {
                    "type": { "type": "string", "const": "kotlinx.schema.generator.json.SealedClassNameCollisionTest.ResultA.Unknown" },
                    "code": {
                      "type": "integer"
                    }
                  },
                  "required": [
                    "type",
                    "code"
                  ],
                  "additionalProperties": false
                },
                "kotlinx.schema.generator.json.SealedClassNameCollisionTest.ResultB": {
                  "oneOf": [
                    { "$ref": "#/$defs/kotlinx.schema.generator.json.SealedClassNameCollisionTest.ResultB.Success" },
                    { "$ref": "#/$defs/kotlinx.schema.generator.json.SealedClassNameCollisionTest.ResultB.Unknown" }
                  ],
                  "description": "Result type B"
                },
                "kotlinx.schema.generator.json.SealedClassNameCollisionTest.ResultB.Success": {
                  "type": "object",
                  "description": "Success result for B",
                  "properties": {
                    "type": { "type": "string", "const": "kotlinx.schema.generator.json.SealedClassNameCollisionTest.ResultB.Success" },
                    "data": {
                      "type": "integer"
                    }
                  },
                  "required": [
                    "type",
                    "data"
                  ],
                  "additionalProperties": false
                },
                "kotlinx.schema.generator.json.SealedClassNameCollisionTest.ResultB.Unknown": {
                  "type": "object",
                  "description": "Unknown error for B",
                  "properties": {
                    "type": { "type": "string", "const": "kotlinx.schema.generator.json.SealedClassNameCollisionTest.ResultB.Unknown" },
                    "message": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "type",
                    "message"
                  ],
                  "additionalProperties": false
                }
              }
            }
            """.trimIndent()
    }
}
