package dev.inmo.postssystem.features.roles.common

import dev.inmo.postssystem.features.users.common.UserId
import kotlinx.serialization.Serializable

@Serializable
sealed class RoleSubject
@Serializable
data class OtherRoleRoleSubject(@Serializable(RoleSerializer::class) val role: Role) : RoleSubject()
@Serializable
data class UserRoleSubject(val userId: UserId) : RoleSubject()

interface ReadRolesStorage<T : Role> {
    suspend fun getSubjects(role: T): List<RoleSubject>
    suspend fun getRoles(subject: RoleSubject): List<T>
    suspend fun getRoles(userId: UserId): List<T> = getRoles(UserRoleSubject(userId))
    suspend fun contains(subject: RoleSubject, role: T): Boolean
    suspend fun containsAny(subject: RoleSubject, roles: List<T>): Boolean
}
suspend fun ReadRolesStorage<Role>.getUsers(
    userRole: Role
): List<UserId> = getSubjects(userRole).flatMap {
    when (it) {
        is OtherRoleRoleSubject -> getUsers(it.role)
        is UserRoleSubject -> listOf(it.userId)
    }
}
suspend fun ReadRolesStorage<Role>.contains(
    userId: UserId,
    userRole: Role
): Boolean = getSubjects(userRole).any {
    when (it) {
        is OtherRoleRoleSubject -> contains(userId, it.role)
        is UserRoleSubject -> userId == it.userId
    }
}
interface WriteRolesStorage<T : Role> {
    suspend fun include(subject: RoleSubject, role: T): Boolean
    suspend fun exclude(subject: RoleSubject, role: T): Boolean
}

interface RolesStorage<T : Role> : ReadRolesStorage<T>, WriteRolesStorage<T>
