package de.krisenvorrat.server.plugins

import de.krisenvorrat.server.model.ErrorResponse
import de.krisenvorrat.server.repository.InventoryRepository
import de.krisenvorrat.server.repository.MessageRepository
import de.krisenvorrat.server.repository.UserRepository
import de.krisenvorrat.server.routes.adminRoutes
import de.krisenvorrat.server.routes.authRoutes
import de.krisenvorrat.server.routes.inventoryRoutes
import de.krisenvorrat.server.routes.messageRoutes
import de.krisenvorrat.server.routes.userRoutes
import de.krisenvorrat.server.routes.versionRoutes
import de.krisenvorrat.server.routes.webSocketRoutes
import de.krisenvorrat.server.security.JwtService
import de.krisenvorrat.server.websocket.WebSocketManager
import io.ktor.http.*
import io.ktor.server.application.*
import io.ktor.server.auth.*
import io.ktor.server.http.content.*
import io.ktor.server.plugins.*
import io.ktor.server.plugins.ratelimit.*
import io.ktor.server.request.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
import io.ktor.server.websocket.*
import java.io.File
import kotlin.time.Duration.Companion.seconds

private const val MAX_BODY_SIZE = 1 * 1024 * 1024L // 1 MB

internal fun Application.configureRouting(
    inventoryRepository: InventoryRepository = InventoryRepository(),
    userRepository: UserRepository = UserRepository(),
    messageRepository: MessageRepository = MessageRepository(),
    jwtService: JwtService = JwtService(environment.config),
    wsManager: WebSocketManager = WebSocketManager()
) {
    val config = environment.config
    val appVersionCode = config.propertyOrNull("krisenvorrat.appVersionCode")
        ?.getString()?.toIntOrNull() ?: 1
    val appVersionName = config.propertyOrNull("krisenvorrat.appVersionName")
        ?.getString() ?: "1.0.0"

    install(WebSockets) {
        pingPeriod = 15.seconds
        timeout = 30.seconds
    }

    routing {
        intercept(ApplicationCallPipeline.Plugins) {
            val contentLength = call.request.header(HttpHeaders.ContentLength)?.toLongOrNull()
            if (contentLength != null && contentLength > MAX_BODY_SIZE) {
                call.respond(
                    HttpStatusCode.PayloadTooLarge,
                    ErrorResponse(status = 413, message = "Request body too large (max 1 MB)")
                )
                finish()
            }
        }

        get("/api/health") {
            call.respondText("OK", ContentType.Text.Plain, HttpStatusCode.OK)
        }

        // Public version endpoint & homepage
        versionRoutes(appVersionCode, appVersionName)

        // Static APK from filesystem (server/data/)
        staticFiles("/static", File("data"))

        // Public auth endpoints (10 req/min per IP)
        rateLimit(RATE_LIMIT_AUTH) {
            authRoutes(userRepository, jwtService, inventoryRepository)
        }

        // Protected endpoints
        authenticate("auth-jwt") {
            rateLimit(RATE_LIMIT_INVENTORY) {
                inventoryRoutes(inventoryRepository, wsManager)
            }
            rateLimit(RATE_LIMIT_ADMIN) {
                adminRoutes(userRepository, inventoryRepository)
            }
            rateLimit(RATE_LIMIT_MESSAGES) {
                messageRoutes(messageRepository, userRepository, wsManager)
            }
            userRoutes(userRepository)
        }

        // WebSocket – auth via query param ?token=
        webSocketRoutes(wsManager, jwtService, messageRepository)

        // Admin web UI (static)
        staticResources("/admin", "static/admin")
    }
}
