package moe.lava.neon.api

import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonNamingStrategy
import java.time.ZoneId
import kotlin.io.encoding.Base64
import kotlin.uuid.ExperimentalUuidApi
import kotlin.uuid.Uuid

@OptIn(ExperimentalUuidApi::class)
private val storedVendorId = Uuid.random().toString().lowercase()

@OptIn(ExperimentalUuidApi::class)
private val storedLaunchId = Uuid.random().toString().lowercase()

internal data class PlatformProps(
    val device: String,
    val systemLocale: String,
    val osVersion: String,
)

internal expect val platformSuperProps: PlatformProps

object ApiConstants {
    @OptIn(ExperimentalSerializationApi::class)
    val json = Json {
        namingStrategy = JsonNamingStrategy.SnakeCase
        ignoreUnknownKeys = true
        encodeDefaults = true
        // TODO: Distinguish missing vs null fields
        explicitNulls = false
    }

    val superProps = Base64.encode(json.encodeToString(SuperProperties()).encodeToByteArray())
    val baseHeaders = mapOf(
        "X-Debug-Options" to "bugReporterEnabled",
        "X-Discord-Locale" to "en-US",
        "X-Discord-Timezone" to ZoneId.systemDefault().id,
        "X-Super-Properties" to superProps,
    )
    const val userAgent = "Discord-Android/311020;RNA"
    const val gatewayUserAgent = "okhttp/4.12.0"

    // TODO: Desktop uses separate properties
    @Suppress("PropertyName")
    @Serializable
    data class SuperProperties(
        val os: String = "Android",
        val browser: String = "Discord Android",
        val device: String = platformSuperProps.device,
        val system_locale: String = platformSuperProps.systemLocale,
        val has_client_mods: Boolean = false,
        val client_version: String = "311.20 - rn",
        val release_channel: String = "googleRelease",
        val device_vendor_id: String = storedVendorId,
        val design_id: Int = 2,
        val browser_user_agent: String = "",
        val browser_version: String = "",
        val os_version: String = platformSuperProps.osVersion,
        val client_build_number: Long = 31102000334720,
        val client_event_source: String? = null,
        val client_launch_id: String = storedLaunchId,
        // TODO: this is a random snowflake
        val launch_signature: String = "1769227908736837151",
        val client_app_state: String = "active",
    )

    // *Ideally* we extend the previous class, but pretty much every way
    // I came up with to do it looks disgusting (I'm open to suggestions though!)
    @Suppress("PropertyName")
    @Serializable
    data class GatewayProperties(
        val os: String = "Android",
        val browser: String = "Discord Android",
        val device: String = platformSuperProps.device,
        val system_locale: String = platformSuperProps.systemLocale,
        val has_client_mods: Boolean = false,
        val client_version: String = "311.20 - rn",
        val release_channel: String = "googleRelease",
        val device_vendor_id: String = storedVendorId,
        val design_id: Int = 2,
        val browser_user_agent: String = "",
        val browser_version: String = "",
        val os_version: String = platformSuperProps.osVersion,
        val client_build_number: Long = 31102000334720,
        val client_event_source: String? = null,
        val client_launch_id: String = storedLaunchId,
        // TODO: this is a random snowflake
        val launch_signature: String = "1769227908736837151",
        val client_app_state: String = "active",

        val is_fast_connect: Boolean = true,
        val gateway_connect_reasons: String = "executeRunnable:Main",
    )
}
