package dev.inmo.postssystem.features.roles.server

import dev.inmo.postssystem.features.auth.common.AuthToken
import dev.inmo.postssystem.features.auth.server.principal
import dev.inmo.postssystem.features.auth.server.tokens.AuthTokensService
import dev.inmo.postssystem.features.common.server.sessions.ApplicationAuthenticationConfigurator
import dev.inmo.postssystem.features.roles.common.Role
import dev.inmo.postssystem.features.roles.common.RolesStorage
import io.ktor.application.call
import io.ktor.auth.Authentication
import io.ktor.auth.session
import io.ktor.http.HttpStatusCode
import io.ktor.response.respond

class RolesAuthenticationConfigurator<T : Role>(
    private val usersRolesStorage: RolesStorage<T>,
    private val authTokensService: AuthTokensService,
    private val rolesCheckers: List<RolesChecker<T>>
) : ApplicationAuthenticationConfigurator.Element {
    override fun Authentication.Configuration.invoke() {
        rolesCheckers.forEach { checker ->
            session<AuthToken>(checker.key) {
                validate {
                    val result = authTokensService.getUserPrincipal(it)
                    if (result.isSuccess) {
                        val user = result.getOrThrow().principal()
                        if (checker.run { invoke(usersRolesStorage, user.user) }) {
                            user
                        } else {
                            null
                        }
                    } else {
                        null
                    }
                }
                challenge { call.respond(HttpStatusCode.Unauthorized) }
            }
        }
    }
}
