package dev.kaizen.app.net

import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue

/**
 * Single source of truth for "are we signed in, and against which instance".
 * Restores the persisted [ServerConfig] on construction, so a returning user lands
 * straight in the chat without re-authenticating. [config] is Compose snapshot
 * state — MainActivity reads it to route between LoginScreen and ChatScreen.
 *
 * Held at Activity scope (instantiated directly like SettingsViewModel) — no DI yet.
 */
data class VersionSkew(val serverVersion: Int, val expectedVersion: Int)

class SessionViewModel(val store: SecureStore) {

    var config by mutableStateOf(store.load())
        private set

    /** Favorite model ids (pinned to the top of the picker), as Compose snapshot state. */
    var favorites by mutableStateOf(store.loadFavorites())
        private set

    var versionSkew by mutableStateOf<VersionSkew?>(null)
        private set

    val isLoggedIn: Boolean get() = config != null

    fun dismissVersionWarning() { versionSkew = null }

    /**
     * In-app login: mint a token, then resolve the user's default model from the
     * server (falling back to [DEFAULT_MODEL]). On success the config is persisted
     * encrypted and [config] flips, which routes the UI into the chat.
     */
    suspend fun login(baseUrlInput: String, email: String, password: String, deviceName: String): LoginResult {
        val baseUrl = normalizeBaseUrl(baseUrlInput)
        return when (val result = KaizenApi.login(baseUrl, email, password, deviceName)) {
            is LoginResult.Success -> {
                val model = KaizenApi.fetchDefaultModel(baseUrl, result.token) ?: DEFAULT_MODEL
                val cfg = ServerConfig(baseUrl = baseUrl, token = result.token, model = model, email = email.trim())
                store.save(cfg)
                config = cfg
                checkServerVersion(baseUrl)
                result
            }
            else -> result
        }
    }

    suspend fun checkServerVersion(baseUrl: String) {
        val meta = KaizenApi.fetchMeta(baseUrl) ?: return
        if (meta.apiVersion != EXPECTED_API_VERSION) {
            versionSkew = VersionSkew(meta.apiVersion, EXPECTED_API_VERSION)
        } else {
            versionSkew = null
        }
    }

    /** Switch the chat model (persisted). No-op if not logged in. */
    fun setModel(modelId: String) {
        val cfg = config ?: return
        if (cfg.model == modelId) return
        val updated = cfg.copy(model = modelId)
        store.save(updated)
        config = updated
    }

    /** Switch the response-speed preset (persisted). */
    fun setSpeed(speed: ChatSpeed) {
        val cfg = config ?: return
        if (cfg.speed == speed) return
        val updated = cfg.copy(speed = speed)
        store.save(updated)
        config = updated
    }

    /** Toggle a model id in/out of favorites (persisted). */
    fun toggleFavorite(modelId: String) {
        val next = favorites.toMutableSet().apply { if (!add(modelId)) remove(modelId) }
        store.saveFavorites(next)
        favorites = next
    }

    fun logout() {
        store.clear()
        config = null
        favorites = emptySet()
    }
}
