package com.rosetta.messenger.database

import android.content.Context
import com.rosetta.messenger.crypto.CryptoManager
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.withContext
import java.time.Instant

/**
 * Service for secure database operations
 * Matches the architecture from React Native app
 */
class DatabaseService(context: Context) {
    private val database = RosettaDatabase.getDatabase(context)
    private val accountDao = database.accountDao()
    
    // 🚀 ОПТИМИЗАЦИЯ: LRU кэш для зашифрованных аккаунтов (избегаем повторных запросов к БД)
    private val accountCache = mutableMapOf<String, EncryptedAccountEntity>()
    private val cacheMaxSize = 10

    companion object {
        private const val TAG = "DatabaseService"

        @Volatile
        private var INSTANCE: DatabaseService? = null

        fun getInstance(context: Context): DatabaseService {
            return INSTANCE ?: synchronized(this) {
                val instance = DatabaseService(context.applicationContext)
                INSTANCE = instance
                instance
            }
        }
    }

    /**
     * Saves encrypted account to database
     */
    suspend fun saveEncryptedAccount(
        publicKey: String,
        privateKeyEncrypted: String,
        seedPhraseEncrypted: String
    ): Boolean = withContext(Dispatchers.IO) {
        try {
            val account = EncryptedAccountEntity(
                publicKey = publicKey,
                privateKeyEncrypted = privateKeyEncrypted,
                seedPhraseEncrypted = seedPhraseEncrypted,
                createdAt = Instant.now().toString(),
                lastUsed = Instant.now().toString(),
                isActive = true
            )

            accountDao.insertAccount(account)
            
            // 🚀 ОПТИМИЗАЦИЯ: Обновляем кэш после сохранения
            accountCache[publicKey] = account
            
            true
        } catch (e: Exception) {
            false
        }
    }

    /**
     * Loads encrypted account from database
     * 🚀 ОПТИМИЗАЦИЯ: Использует кэш для избежания повторных запросов
     */
    suspend fun getEncryptedAccount(publicKey: String): EncryptedAccountEntity? =
        withContext(Dispatchers.IO) {
            try {
                // Проверяем кэш сначала
                accountCache[publicKey]?.let { return@withContext it }
                
                // Загружаем из БД и кэшируем
                val account = accountDao.getAccount(publicKey)
                account?.let {
                    accountCache[publicKey] = it
                    // Ограничиваем размер кэша
                    if (accountCache.size > cacheMaxSize) {
                        accountCache.remove(accountCache.keys.first())
                    }
                }
                account
            } catch (e: Exception) {
                null
            }
        }

    /**
     * Gets all encrypted accounts
     */
    suspend fun getAllEncryptedAccounts(): List<EncryptedAccountEntity> =
        withContext(Dispatchers.IO) {
            try {
                accountDao.getAllAccounts()
            } catch (e: Exception) {
                emptyList()
            }
        }

    /**
     * Gets all accounts as Flow for reactive updates
     */
    fun getAllAccountsFlow(): Flow<List<EncryptedAccountEntity>> {
        return accountDao.getAllAccountsFlow()
    }

    /**
     * Updates last used timestamp for account
     */
    suspend fun updateLastUsed(publicKey: String) = withContext(Dispatchers.IO) {
        try {
            accountDao.updateLastUsed(publicKey, Instant.now().toString())
        } catch (e: Exception) {
        }
    }

    /**
     * Deletes account from database
     */
    suspend fun deleteAccount(publicKey: String): Boolean = withContext(Dispatchers.IO) {
        try {
            accountDao.deleteAccount(publicKey)
            true
        } catch (e: Exception) {
            false
        }
    }

    /**
     * Checks if any accounts exist
     */
    suspend fun hasAccounts(): Boolean = withContext(Dispatchers.IO) {
        try {
            accountDao.getAccountCount() > 0
        } catch (e: Exception) {
            false
        }
    }

    /**
     * Decrypts account with password
     * Returns decrypted private key and seed phrase
     */
    suspend fun decryptAccount(
        publicKey: String,
        password: String
    ): DecryptedAccountData? = withContext(Dispatchers.IO) {
        try {
            val encryptedAccount = getEncryptedAccount(publicKey) ?: run {
                return@withContext null
            }

            // Decrypt private key
            val privateKey = try {
                CryptoManager.decryptWithPassword(
                    encryptedAccount.privateKeyEncrypted,
                    password
                ) ?: run {
                    return@withContext null
                }
            } catch (e: Exception) {
                return@withContext null
            }

            // Decrypt seed phrase
            val seedPhraseString = try {
                CryptoManager.decryptWithPassword(
                    encryptedAccount.seedPhraseEncrypted,
                    password
                ) ?: run {
                    return@withContext null
                }
            } catch (e: Exception) {
                return@withContext null
            }

            val seedPhrase = seedPhraseString.split(" ")

            // Generate private key hash for protocol
            val privateKeyHash = CryptoManager.generatePrivateKeyHash(privateKey)

            DecryptedAccountData(
                publicKey = publicKey,
                privateKey = privateKey,
                privateKeyHash = privateKeyHash,
                seedPhrase = seedPhrase
            )
        } catch (e: Exception) {
            null
        }
    }
}

/**
 * Decrypted account data
 */
data class DecryptedAccountData(
    val publicKey: String,
    val privateKey: String,
    val privateKeyHash: String,
    val seedPhrase: List<String>
)
