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

import com.runicgateway.app.data.api.dto.ChangePasswordRequest
import com.runicgateway.app.data.api.dto.ChangeUsernameRequest
import com.runicgateway.app.data.api.dto.LinkedIdentityDto
import com.runicgateway.app.data.api.dto.PlayerAccountDto
import com.runicgateway.app.data.api.dto.RecoveryCodesDto
import com.runicgateway.app.data.api.dto.RecoveryGenerateRequest
import com.runicgateway.app.data.api.dto.RecoveryStatusDto
import com.runicgateway.app.data.api.dto.RevokedCountDto
import com.runicgateway.app.data.api.dto.RevokedFlagDto
import com.runicgateway.app.data.api.dto.TotpCodeRequest
import com.runicgateway.app.data.api.dto.TotpSetupDto
import com.runicgateway.app.data.api.dto.TotpStateDto
import com.runicgateway.app.data.api.dto.TrustDeviceRequest
import com.runicgateway.app.data.api.dto.TrustDeviceResultDto
import com.runicgateway.app.data.api.dto.TrustedDeviceDto
import com.runicgateway.app.data.api.dto.UsernameResponse
import retrofit2.Response
import retrofit2.http.Body
import retrofit2.http.DELETE
import retrofit2.http.GET
import retrofit2.http.HTTP
import retrofit2.http.PATCH
import retrofit2.http.POST
import retrofit2.http.Path

/**
 * The role-agnostic self-service surface (PLAN.md §6.3, §6.4): account, credential
 * changes, TOTP enrollment, and linked SSO identities under `/auth/me/account*`.
 * The app calls these regardless of role and never touches `/admin`. Every call
 * rides the main client, so [com.runicgateway.app.core.net.AuthInterceptor] attaches
 * the bearer and [com.runicgateway.app.core.net.TokenAuthenticator] refreshes on 401.
 */
interface MeApi {

    @GET("api/v1/auth/me/account")
    suspend fun getAccount(): PlayerAccountDto

    @PATCH("api/v1/auth/me/account/username")
    suspend fun changeUsername(@Body body: ChangeUsernameRequest): UsernameResponse

    @PATCH("api/v1/auth/me/account/password")
    suspend fun changePassword(@Body body: ChangePasswordRequest): Unit

    @POST("api/v1/auth/me/account/totp/setup")
    suspend fun totpSetup(): TotpSetupDto

    @POST("api/v1/auth/me/account/totp/enable")
    suspend fun totpEnable(@Body body: TotpCodeRequest): TotpStateDto

    @POST("api/v1/auth/me/account/totp/disable")
    suspend fun totpDisable(@Body body: TotpCodeRequest): TotpStateDto

    @GET("api/v1/auth/me/account/identities")
    suspend fun identities(): List<LinkedIdentityDto>

    // DELETE with no body — a plain @DELETE would suffice, but @HTTP keeps the
    // path template explicit alongside the provider argument.
    @HTTP(method = "DELETE", path = "api/v1/auth/me/account/identities/{provider}")
    suspend fun unlinkIdentity(@Path("provider") provider: String): Unit

    // ── Trusted devices (TRUSTED_DEVICES_MFA.md) — devices allowed to skip TOTP ──

    @GET("api/v1/auth/me/trusted-devices")
    suspend fun trustedDevices(): List<TrustedDeviceDto>

    // Raw [Response] so the caller can read the `409 { error, devices }` cap body,
    // which a thrown HttpException would discard.
    @POST("api/v1/auth/me/trusted-devices")
    suspend fun trustThisDevice(@Body body: TrustDeviceRequest): Response<TrustDeviceResultDto>

    @DELETE("api/v1/auth/me/trusted-devices/{id}")
    suspend fun revokeTrustedDevice(@Path("id") id: Long): RevokedFlagDto

    @DELETE("api/v1/auth/me/trusted-devices")
    suspend fun revokeAllTrustedDevices(): RevokedCountDto

    // ── Recovery (backup) codes ──────────────────────────────────────────────

    @GET("api/v1/auth/me/account/recovery-codes/status")
    suspend fun recoveryCodesStatus(): RecoveryStatusDto

    @POST("api/v1/auth/me/account/recovery-codes/generate")
    suspend fun generateRecoveryCodes(@Body body: RecoveryGenerateRequest): RecoveryCodesDto
}
