package space.nstart.pcp.pcp_request_service.message

import org.junit.jupiter.api.Test
import java.nio.file.Files
import java.nio.file.Path
import kotlin.io.path.readText
import kotlin.test.assertEquals
import kotlin.test.assertNotNull
import kotlin.test.assertTrue

class SatelliteDeletedKafkaListenerGroupIdTest {

    private val listeners = mapOf(
        "slots-service" to ListenerExpectation(
            path = "services/slots-service/src/main/kotlin/space/nstart/pcp/slots_service/service/SatelliteDeletedKafkaListener.kt",
            groupId = "pcp-slots-service-satellite-deleted",
            hasEventFilter = true
        ),
        "pcp-ballistics-service" to ListenerExpectation(
            path = "services/pcp-ballistics-service/src/main/kotlin/space/nstart/pcp/pcp_request_service/message/SatelliteDeletedKafkaListener.kt",
            groupId = "pcp-ballistics-service-satellite-deleted",
            hasEventFilter = true
        ),
        "tle-monitoring-service" to ListenerExpectation(
            path = "services/tle-monitoring-service/src/main/kotlin/space/nstart/pcp/tle_monitoring_service/message/SatelliteDeletedKafkaListener.kt",
            groupId = "pcp-tle-monitoring-service-satellite-deleted",
            hasEventFilter = true
        ),
        "pcp-complex-mission-service" to ListenerExpectation(
            path = "services/pcp-complex-mission-service/src/main/kotlin/space/nstart/pcp/pcp_satellites_service/service/SatelliteDeletedKafkaListener.kt",
            groupId = "pcp-complex-mission-service-satellite-deleted"
        ),
        "pcp-mission-planing-service" to ListenerExpectation(
            path = "services/pcp-mission-planing-service/src/main/kotlin/space/nstart/pcp/pcp_mission_planing_service/service/SatelliteDeletedKafkaListener.kt",
            groupId = "pcp-mission-planing-service-satellite-deleted"
        ),
        "pcp-dynamic-plan-service" to ListenerExpectation(
            path = "services/pcp-dynamic-plan-service/src/main/kotlin/space/nstart/pcp/complan/service/SatelliteDeletedKafkaListener.kt",
            groupId = "pcp-dynamic-plan-service-satellite-deleted"
        )
    )

    @Test
    fun `satellite deleted listeners use unique explicit consumer groups`() {
        val resolvedGroupIds = listeners.mapValues { (_, expectation) ->
            val source = projectRoot().resolve(expectation.path).readText()
            val annotationBody = kafkaListenerAnnotationBody(source)
            val groupReference = annotationParameter(annotationBody, "groupId")
            assertNotNull(groupReference, "SatelliteDeletedEvent listener must define explicit groupId: ${expectation.path}")
            assertEquals("SATELLITE_DELETED_CONSUMER_GROUP", groupReference)
            assertTrue(
                annotationBody.contains("""topics = ["\${'$'}{app.kafka.topics.satellites:pcp.satellites}"]"""),
                "SatelliteDeletedEvent listener must keep satellite topic: ${expectation.path}"
            )
            if (expectation.hasEventFilter) {
                assertTrue(
                    annotationBody.contains("""filter = "satelliteDeletedFilter""""),
                    "SatelliteDeletedEvent listener must keep event filter: ${expectation.path}"
                )
            }

            val groupId = consumerGroupConstantValue(source)
            assertEquals(expectation.groupId, groupId)
            groupId
        }

        assertEquals(
            resolvedGroupIds.size,
            resolvedGroupIds.values.toSet().size,
            "SatelliteDeletedEvent consumer groups must be unique per service: $resolvedGroupIds"
        )
    }

    private fun kafkaListenerAnnotationBody(source: String): String {
        val match = Regex("@KafkaListener\\((.*?)\\)", RegexOption.DOT_MATCHES_ALL).find(source)
        assertNotNull(match, "SatelliteDeletedEvent listener must have @KafkaListener")
        return match.groupValues[1]
    }

    private fun annotationParameter(annotationBody: String, parameterName: String): String? =
        Regex("""$parameterName\s*=\s*([^,\n)]+)""")
            .find(annotationBody)
            ?.groupValues
            ?.get(1)
            ?.trim()

    private fun consumerGroupConstantValue(source: String): String {
        val match = Regex("""private const val SATELLITE_DELETED_CONSUMER_GROUP\s*=\s*"([^"]+)"""").find(source)
        assertNotNull(match, "SatelliteDeletedEvent listener must declare SATELLITE_DELETED_CONSUMER_GROUP")
        return match.groupValues[1]
    }

    private fun projectRoot(): Path {
        generateSequence(Path.of(System.getProperty("user.dir")).toAbsolutePath()) { it.parent }
            .firstOrNull { Files.exists(it.resolve("settings.gradle.kts")) }
            ?.let { return it }

        error("Cannot locate project root from ${System.getProperty("user.dir")}")
    }

    private data class ListenerExpectation(
        val path: String,
        val groupId: String,
        val hasEventFilter: Boolean = false
    )
}
