package de.krisenvorrat.server.routes

import de.krisenvorrat.server.repository.MessageRepository
import de.krisenvorrat.server.security.JwtService
import de.krisenvorrat.server.websocket.WebSocketManager
import io.ktor.server.routing.*
import io.ktor.server.websocket.*
import io.ktor.websocket.*
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.buildJsonObject
import kotlinx.serialization.json.put

internal fun Route.webSocketRoutes(
    wsManager: WebSocketManager,
    jwtService: JwtService,
    messageRepository: MessageRepository
) {
    webSocket("/ws/sync") {
        val token = call.request.queryParameters["token"]
        if (token == null) {
            close(CloseReason(CloseReason.Codes.VIOLATED_POLICY, "Missing token"))
            return@webSocket
        }
        val principal = jwtService.verifier.runCatching { verify(token) }.getOrNull()
        val userId = principal?.getClaim("userId")?.asString()
        val tokenType = principal?.getClaim("type")?.asString()
        if (userId == null || tokenType != "access") {
            close(CloseReason(CloseReason.Codes.VIOLATED_POLICY, "Invalid or expired token"))
            return@webSocket
        }
        wsManager.addSession(userId, this)
        val pending = messageRepository.getUndelivered(userId)
        for (msg in pending) {
            val payload = Json.encodeToString(buildJsonObject {
                put("type", "new_message")
                put("id", msg.id)
                put("senderId", msg.senderId)
                put("senderUsername", msg.senderUsername)
                put("receiverId", msg.receiverId)
                put("body", msg.body)
                put("sentAt", msg.sentAt)
            })
            send(Frame.Text(payload))
        }
        if (pending.isNotEmpty()) {
            messageRepository.markAllDeliveredForReceiver(userId)
        }
        try {
            for (frame in incoming) {
                // Client frames are accepted but not processed (server push only)
            }
        } finally {
            wsManager.removeSession(userId, this)
        }
    }
}
