package com.rosetta.messenger.data import android.content.Context import androidx.datastore.core.DataStore import androidx.datastore.preferences.core.* import androidx.datastore.preferences.preferencesDataStore import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.map private val Context.accountDataStore: DataStore by preferencesDataStore(name = "account_store") /** * Manages encrypted account storage using DataStore */ class AccountManager(private val context: Context) { companion object { private val CURRENT_PUBLIC_KEY = stringPreferencesKey("current_public_key") private val ACCOUNTS_JSON = stringPreferencesKey("accounts_json") private val IS_LOGGED_IN = booleanPreferencesKey("is_logged_in") private const val PREFS_NAME = "rosetta_account_prefs" private const val KEY_LAST_LOGGED = "last_logged_public_key" } // Use SharedPreferences for last logged account - more reliable for immediate reads private val sharedPrefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE) val currentPublicKey: Flow = context.accountDataStore.data.map { preferences -> preferences[CURRENT_PUBLIC_KEY] } val isLoggedIn: Flow = context.accountDataStore.data.map { preferences -> preferences[IS_LOGGED_IN] ?: false } val accountsJson: Flow = context.accountDataStore.data.map { preferences -> preferences[ACCOUNTS_JSON] } // Synchronous read from SharedPreferences - always up to date fun getLastLoggedPublicKey(): String? { val publicKey = sharedPrefs.getString(KEY_LAST_LOGGED, null) return publicKey } // Synchronous write to SharedPreferences fun setLastLoggedPublicKey(publicKey: String) { val success = sharedPrefs.edit().putString(KEY_LAST_LOGGED, publicKey).commit() // commit() is synchronous // Verify immediately val saved = sharedPrefs.getString(KEY_LAST_LOGGED, null) } suspend fun saveAccount(account: EncryptedAccount) { context.accountDataStore.edit { preferences -> val existingJson = preferences[ACCOUNTS_JSON] val accounts = if (existingJson != null) { parseAccounts(existingJson).toMutableList() } else { mutableListOf() } // Remove existing account with same public key accounts.removeAll { it.publicKey == account.publicKey } accounts.add(account) preferences[ACCOUNTS_JSON] = serializeAccounts(accounts) } } suspend fun getAccount(publicKey: String): EncryptedAccount? { val preferences = context.accountDataStore.data.first() val json = preferences[ACCOUNTS_JSON] return if (json != null) parseAccounts(json).find { it.publicKey == publicKey } else null } suspend fun getAllAccounts(): List { val preferences = context.accountDataStore.data.first() val json = preferences[ACCOUNTS_JSON] return if (json != null) parseAccounts(json) else emptyList() } suspend fun setCurrentAccount(publicKey: String) { // ⚡ ВАЖНО: Сначала сохраняем в SharedPreferences синхронно setLastLoggedPublicKey(publicKey) // Потом в DataStore асинхронно (для совместимости с потоками) context.accountDataStore.edit { preferences -> preferences[CURRENT_PUBLIC_KEY] = publicKey preferences[IS_LOGGED_IN] = true } } suspend fun logout() { context.accountDataStore.edit { preferences -> preferences[IS_LOGGED_IN] = false } } suspend fun clearAll() { context.accountDataStore.edit { it.clear() } } private fun serializeAccounts(accounts: List): String { return accounts.joinToString("|||") { account -> "${account.publicKey}::${account.encryptedPrivateKey}::${account.encryptedSeedPhrase}::${account.name}" } } private fun parseAccounts(json: String): List { if (json.isBlank()) return emptyList() return json.split("|||").mapNotNull { accountStr -> val parts = accountStr.split("::") if (parts.size >= 4) { EncryptedAccount( publicKey = parts[0], encryptedPrivateKey = parts[1], encryptedSeedPhrase = parts[2], name = parts[3] ) } else null } } } data class EncryptedAccount( val publicKey: String, val encryptedPrivateKey: String, val encryptedSeedPhrase: String, val name: String = "Account" ) data class DecryptedAccount( val publicKey: String, val privateKey: String, val seedPhrase: List, val privateKeyHash: String, val name: String = "Account" )