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

import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test

/**
 * Encode/decode tests for the mobile bearer-auth request bodies (`/auth/mobile/…`)
 * and the token pair — the snake_case `device_name`, the omit-nulls behaviour, and
 * the trusted-device outcome fields on the login response.
 */
class AuthRequestDtoTest {

    private val json = Json {
        ignoreUnknownKeys = true
        explicitNulls = false
        coerceInputValues = true
    }

    @Test fun loginRequestEncodesSnakeCaseDeviceNameAndOmitsNulls() {
        val body = json.encodeToString(
            MobileLoginRequest(username = "gwen", password = "pw", trustDevice = true, device_name = "Pixel 8"),
        )
        assertTrue(body.contains("\"username\":\"gwen\""))
        assertTrue(body.contains("\"device_name\":\"Pixel 8\""))
        assertTrue(body.contains("\"trustDevice\":true"))
        assertFalse(body.contains("\"code\"")) // null omitted (explicitNulls = false)
    }

    @Test fun loginRequestCarriesSecondFactorOnRetry() {
        val withCode = json.encodeToString(MobileLoginRequest("u", "p", code = "123456"))
        assertTrue(withCode.contains("\"code\":\"123456\""))
        val withRecovery = json.encodeToString(MobileLoginRequest("u", "p", recoveryCode = "aaaa-1111"))
        assertTrue(withRecovery.contains("\"recoveryCode\":\"aaaa-1111\""))
    }

    @Test fun refreshAndLogoutBodiesEncode() {
        assertTrue(json.encodeToString(MobileRefreshRequest("rt")).contains("\"refreshToken\":\"rt\""))
        assertTrue(json.encodeToString(MobileLogoutRequest(all = true)).contains("\"all\":true"))
    }

    @Test fun tokenResponseDecodesTrustOutcome() {
        val dto = json.decodeFromString<MobileTokenResponse>(
            """{"accessToken":"a","refreshToken":"r","expiresIn":"15m",
                "user":{"id":1,"username":"gwen","role":"player"},
                "trustToken":"opaque"}""",
        )
        assertEquals("a", dto.accessToken)
        assertEquals("opaque", dto.trustToken)
        assertFalse(dto.trustLimitReached)
        assertEquals("gwen", dto.user.username)
    }

    @Test fun tokenResponseDecodesTrustLimitReached() {
        val dto = json.decodeFromString<MobileTokenResponse>(
            """{"accessToken":"a","refreshToken":"r","user":{"id":1,"username":"g","role":"player"},
                "trustLimitReached":true,"devices":[{"id":1,"platform":"web","deviceName":"FF"}]}""",
        )
        assertTrue(dto.trustLimitReached)
        assertEquals(1, dto.devices.size)
    }
}
