/*
 * SPDX-License-Identifier: GPL-3.0-or-later
 */
package com.runicgateway.app.core.auth

import com.runicgateway.app.data.api.dto.SafeUserDto

/**
 * The signed-in identity the app carries (PLAN.md §4.3, §5). Role is *advisory*
 * for menu rendering only — the backend re-checks every gated call, so the app
 * treats a 403 as authoritative and never assumes access from this value.
 */
data class SessionUser(
    val id: Long,
    val username: String,
    val role: Role,
) {
    val isPlayer: Boolean get() = role == Role.PLAYER

    /** Any staff role (moderator/editor/admin) — the staff-operations surface (§1, M10). */
    val isStaff: Boolean get() = role.isStaff

    /** Admin or moderator — moderation actions + the support queue (`modAccess`). */
    val isModerator: Boolean get() = role == Role.ADMIN || role == Role.MODERATOR

    /** Admin only — site-mode and other `adminOnly` controls. */
    val isAdmin: Boolean get() = role == Role.ADMIN
}

/**
 * The account roles the backend issues. The three staff roles are gated by
 * capability, not rank (PLAN.md §5); [UNKNOWN] absorbs any future role so an
 * additive backend change never crashes the menu.
 */
enum class Role(val wire: String) {
    PLAYER("player"),
    MODERATOR("moderator"),
    EDITOR("editor"),
    ADMIN("admin"),
    UNKNOWN("");

    val isStaff: Boolean get() = this == MODERATOR || this == EDITOR || this == ADMIN

    companion object {
        fun fromWire(value: String?): Role =
            entries.firstOrNull { it.wire.equals(value, ignoreCase = true) } ?: UNKNOWN
    }
}

/** The two auth states the UI observes. */
sealed interface Session {
    data object SignedOut : Session
    data class SignedIn(val user: SessionUser) : Session
}

internal fun SafeUserDto.toSessionUser(): SessionUser =
    SessionUser(id = id, username = username, role = Role.fromWire(role))

internal fun SafeUserDto.toStored(accessToken: String, refreshToken: String): StoredSession =
    StoredSession(
        accessToken = accessToken,
        refreshToken = refreshToken,
        userId = id,
        username = username,
        role = role,
    )

internal fun StoredSession.toSessionUser(): SessionUser =
    SessionUser(id = userId, username = username, role = Role.fromWire(role))
