package moe.lava.neon.core.repository

import co.touchlab.kermit.Logger
import dev.zacsweers.metro.AppScope
import dev.zacsweers.metro.Inject
import dev.zacsweers.metro.SingleIn
import io.ktor.client.call.body
import io.ktor.client.request.get
import io.ktor.client.request.header
import io.ktor.client.request.parameter
import io.ktor.client.request.post
import io.ktor.client.request.setBody
import io.ktor.http.ContentType
import io.ktor.http.contentType
import kotlinx.serialization.Serializable
import moe.lava.neon.core.AppSettings
import moe.lava.neon.core.api.ApiClient

@Serializable
private data class ExperimentResponse(
    val fingerprint: String,
)

@Serializable
private data class LoginRequest(
    val login: String,
    val password: String,
    val undelete: Boolean = false,
    val loginSource: String? = null,
    val giftCodeSkuId: String? = null,
)

@Serializable
private data class LoginResponse(
    val userId: String,
    val token: String,
    val userSettings: UserSettings,
) {
    @Serializable
    data class UserSettings(val locale: String, val theme: String)
}

sealed class AuthResponse {
    data class Success(val token: String) : AuthResponse()
    // TODO
//    data class MFARequested() : AuthResponse()
}

@Inject
@SingleIn(AppScope::class)
class AuthRepository(
    private val settings: AppSettings,
    private val api: ApiClient,
) {
    private val logger = Logger.withTag("neon.core.repo/auth")
    var token by settings::token
        private set

    var fingerprint by settings::fingerprint
        private set

    suspend fun login(
        email: String,
        password: String,
    ): AuthResponse {
        if (fingerprint == null) {
            fingerprint = api.client.get("experiments") {
                parameter("with_guild_experiments", "true")
            }.body<ExperimentResponse>().fingerprint
        }

        val res = api.client.post("auth/login") {
            header("X-Fingerprint", fingerprint)
            contentType(ContentType.Application.Json)
            setBody(LoginRequest(
                login = email,
                password = password,
            ))
        }
        val body = res.body<LoginResponse>()
        logger.i { "Login success $body" }
        this.token = body.token
        return AuthResponse.Success(body.token)
    }

    fun login(token: String): String {
        this.token = token
        return token
    }

    fun logout() {
        token = null
    }
}
