package de.arindy.dicetower

import io.quarkus.runtime.annotations.RegisterForReflection
import jakarta.enterprise.context.ApplicationScoped
import jakarta.ws.rs.Consumes
import jakarta.ws.rs.GET
import jakarta.ws.rs.POST
import jakarta.ws.rs.Path
import jakarta.ws.rs.PathParam
import jakarta.ws.rs.Produces
import jakarta.ws.rs.core.Context
import jakarta.ws.rs.core.MediaType
import jakarta.ws.rs.sse.OutboundSseEvent
import jakarta.ws.rs.sse.Sse
import jakarta.ws.rs.sse.SseBroadcaster
import jakarta.ws.rs.sse.SseEventSink
import java.util.UUID

@Path("/dice/{id}")
@ApplicationScoped
final class DiceResource(@Context val sse: Sse) {

    private var eventBuilder: OutboundSseEvent.Builder = sse.newEventBuilder()
    private var sseBroadcasters: MutableMap<String, SseBroadcaster> = HashMap()

    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    fun parseCommand(@PathParam("id") id: String, data: RollPayload) {
        data.roll = data.command.split(" ", "&", "and").filter { it.isNotEmpty() }.map { it.trim() }.toTypedArray<String>()
        data.room = id.split(":")[0]
        data.user = id.split(":")[1]
        sseBroadcasters[id]?.broadcast(
            eventBuilder.id((UUID.randomUUID()).toString())
                .mediaType(MediaType.APPLICATION_JSON_TYPE).data(data).build()
        )
        if (data.roll.all { it.trim().isNotEmpty() }) {
            results(data.room!!, Result(data.name, data.user!!, data.themeColor))
        }
    }

    @POST
    @Path("/register")
    @Consumes(MediaType.APPLICATION_JSON)
    fun register(@PathParam("id") id: String, data: Any) {
        println("id = [${id}], data = [${data}]")
        sseBroadcasters["register:$id"]?.broadcast(
            eventBuilder.id((UUID.randomUUID()).toString())
                .mediaType(MediaType.APPLICATION_JSON_TYPE).data(data).build())

    }

    @POST
    @Path("/results")
    @Consumes(MediaType.APPLICATION_JSON)
    fun results(@PathParam("id") id: String, data: Any) {
        sseBroadcasters[id]?.broadcast(
            eventBuilder.id((UUID.randomUUID()).toString())
                .mediaType(MediaType.APPLICATION_JSON_TYPE).data(data).build()
        )
    }

    @GET
    @Path("/stream")
    @Produces(MediaType.SERVER_SENT_EVENTS)
    fun stream(@PathParam("id") id: String, @Context sseEventSink: SseEventSink) {
        sseBroadcasters[id] = sse.newBroadcaster()
        sseBroadcasters[id]?.register(sseEventSink)
    }

    @GET
    @Path("/results")
    @Produces(MediaType.SERVER_SENT_EVENTS)
    fun results(@PathParam("id") id: String, @Context sseEventSink: SseEventSink) {
        if (!sseBroadcasters.containsKey(id)) {
            sseBroadcasters[id] = sse.newBroadcaster()
        }
        sseBroadcasters[id]?.register(sseEventSink)
    }

    @GET
    @Path("/users")
    @Produces(MediaType.SERVER_SENT_EVENTS)
    fun users(@PathParam("id") id: String, @Context sseEventSink: SseEventSink) {
        if (!sseBroadcasters.containsKey("register:$id")) {
            sseBroadcasters["register:$id"] = sse.newBroadcaster()
        }
        sseBroadcasters["register:$id"]?.register(sseEventSink)
    }

    @RegisterForReflection
    data class Result(val name: String, val user: String, val themeColor: String)

}
