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

import dev.inmo.postssystem.features.roles.common.*
import dev.inmo.micro_utils.ktor.server.*
import dev.inmo.micro_utils.ktor.server.configurators.ApplicationRoutingConfigurator
import io.ktor.auth.authenticate
import io.ktor.routing.*
import kotlinx.serialization.KSerializer
import kotlinx.serialization.builtins.ListSerializer
import kotlinx.serialization.builtins.serializer

class RolesStorageReadServerRoutesConfigurator<T : Role>(
    private val storage: ReadRolesStorage<T>,
    private val serializer: KSerializer<T>,
    private val unifiedRouter: UnifiedRouter
) : ApplicationRoutingConfigurator.Element {
    private val userRolesSerializer = ListSerializer(serializer)
    override fun Route.invoke() {
        unifiedRouter.apply {
            authenticate {
                route(usersRolesRootPathPart) {
                    get(usersRolesGetSubjectsPathPart) {
                        val role = decodeUrlQueryValueOrSendError(usersRolesRoleQueryParameterName, serializer)
                            ?: return@get
                        unianswer(
                            RoleSubjectsSerializer,
                            storage.getSubjects(role)
                        )
                    }

                    get(usersRolesGetRolesPathPart) {
                        val subject = decodeUrlQueryValueOrSendError(
                            usersRolesRoleSubjectQueryParameterName,
                            RoleSubject.serializer()
                        ) ?: return@get
                        unianswer(
                            userRolesSerializer,
                            storage.getRoles(subject)
                        )
                    }

                    get(usersRolesContainsPathPart) {
                        val subject = decodeUrlQueryValueOrSendError(
                            usersRolesRoleSubjectQueryParameterName,
                            RoleSubject.serializer()
                        ) ?: return@get
                        val role = decodeUrlQueryValueOrSendError(
                            usersRolesRoleQueryParameterName,
                            serializer
                        ) ?: return@get
                        unianswer(
                            Boolean.serializer(),
                            storage.contains(subject, role)
                        )
                    }

                    get(usersRolesContainsAnyPathPart) {
                        val subject = decodeUrlQueryValueOrSendError(
                            usersRolesRoleSubjectQueryParameterName,
                            RoleSubject.serializer()
                        ) ?: return@get
                        val userRoles = decodeUrlQueryValueOrSendError(
                            usersRolesRoleQueryParameterName,
                            userRolesSerializer
                        ) ?: return@get
                        unianswer(
                            Boolean.serializer(),
                            storage.containsAny(subject, userRoles)
                        )
                    }
                }
            }
        }
    }
}
