package de.krisenvorrat.server.security

import com.auth0.jwt.JWT
import com.auth0.jwt.algorithms.Algorithm
import com.auth0.jwt.interfaces.JWTVerifier
import io.ktor.server.application.*
import io.ktor.server.auth.*
import io.ktor.server.config.*
import java.util.Date

internal data class UserPrincipal(
    val userId: String,
    val username: String,
    val isAdmin: Boolean
) : Principal

internal class JwtService(config: ApplicationConfig) {

    private val secret: String = config.property("krisenvorrat.jwtSecret").getString()
    val issuer: String = config.property("krisenvorrat.jwtIssuer").getString()
    val audience: String = config.property("krisenvorrat.jwtAudience").getString()
    private val accessExpiryMs: Long = config.property("krisenvorrat.accessTokenExpiryMs").getString().toLong()
    private val refreshExpiryMs: Long = config.property("krisenvorrat.refreshTokenExpiryMs").getString().toLong()

    val verifier: JWTVerifier = JWT.require(Algorithm.HMAC256(secret))
        .withAudience(audience)
        .withIssuer(issuer)
        .build()

    fun generateAccessToken(userId: String, username: String, isAdmin: Boolean): String =
        JWT.create()
            .withAudience(audience)
            .withIssuer(issuer)
            .withClaim("userId", userId)
            .withClaim("username", username)
            .withClaim("isAdmin", isAdmin)
            .withClaim("type", "access")
            .withExpiresAt(Date(System.currentTimeMillis() + accessExpiryMs))
            .sign(Algorithm.HMAC256(secret))

    fun generateRefreshToken(userId: String): String =
        JWT.create()
            .withAudience(audience)
            .withIssuer(issuer)
            .withClaim("userId", userId)
            .withClaim("type", "refresh")
            .withExpiresAt(Date(System.currentTimeMillis() + refreshExpiryMs))
            .sign(Algorithm.HMAC256(secret))

    fun extractRefreshUserId(refreshToken: String): String? = try {
        val decoded = verifier.verify(refreshToken)
        if (decoded.getClaim("type").asString() == "refresh") {
            decoded.getClaim("userId").asString()
        } else null
    } catch (_: Exception) {
        null
    }
}
