/*
 * Copyright (c) 2026 QPQ IaaS AG <info@qpq.swiss>. All rights reserved.
 * Project: Gajumaru Core Java Libraries <gajumaru.io>
 *
 * This program is dual-licensed:
 * 1) Under the GNU Affero General Public License as published by the Free
 *    Software Foundation, either version 3 of the License, or (at your option)
 *    any later version (AGPL-3.0-or-later).
 *
 * 2) Under a commercial/proprietary license available directly from QPQ IaaS AG.
 *    If you wish to use this software outside the strict constraints of the
 *    AGPLv3 (e.g. within a closed-source or proprietary product), you must
 *    purchase a commercial license from QPQ IaaS AG.
 *
 * Authors:
 *   - Craig Everett <craigeverett@qpq.swiss>
 *
 * SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-QPQ-Commercial
 */

package swiss.qpq.gajumobile.data

import android.content.Context
import kotlinx.serialization.json.Json
import swiss.qpq.gajumobile.data.models.Account
import swiss.qpq.gajumobile.data.models.Wallet
import swiss.qpq.gajumobile.security.EncryptionService
import swiss.qpq.gajumobile.security.KeyManager
import swiss.qpq.gajumaru.core.tools.NodeClient
import swiss.qpq.gajumobile.data.models.CachedBalance
import java.io.File
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext

class WalletRepository(private val context: Context) {

    private val json = Json { prettyPrint = true }

    fun saveWallet(wallet: Wallet) {
        val walletJson = json.encodeToString(wallet)
        val envelope = EncryptionService.encrypt(context, walletJson.toByteArray())
        val envelopeJson = json.encodeToString(envelope)
        
        val file = getWalletFile(wallet.id)
        file.writeText(envelopeJson)
    }

    fun deleteWallet(walletId: String) {
        val file = getWalletFile(walletId)
        if (file.exists()) {
            file.delete()
        }
    }

    fun deleteAccount(walletId: String, accountId: String) {
        val wallet = loadWallet(walletId) ?: return
        val updatedAccounts = wallet.accounts.filter { it.id != accountId }
        if (updatedAccounts.isEmpty()) {
            deleteWallet(walletId)
        } else {
            saveWallet(wallet.copy(accounts = updatedAccounts))
        }
    }

    fun loadWallet(walletId: String): Wallet? {
        val file = getWalletFile(walletId)
        if (!file.exists()) return null
        
        return try {
            val envelopeJson = file.readText()
            val envelope = json.decodeFromString<swiss.qpq.gajumobile.security.EncryptedEnvelope>(envelopeJson)
            val walletBytes = EncryptionService.decrypt(context, envelope)
            json.decodeFromString<Wallet>(String(walletBytes))
        } catch (e: Exception) {
            android.util.Log.e("WalletRepository", "Failed to load wallet", e)
            null
        }
    }

    suspend fun refreshAccount(walletId: String, accountId: String): Account? {
        val wallet = loadWallet(walletId) ?: return null
        val account = wallet.accounts.find { it.id == accountId } ?: return null
        
        val client = NodeClient(wallet.endpoints.map { NodeClient.Endpoint(it.host, it.port, it.useTls) })
        return try {
            val accountInfo = withContext(Dispatchers.IO) {
                client.account(account.gajuId)
            }
            
            val balance = accountInfo["balance"]?.toString() ?: "0"
            
            val updatedAccount = account.copy(
                cachedBalance = CachedBalance(
                    totalPucks = balance,
                    chainId = wallet.networkId,
                    timestamp = System.currentTimeMillis()
                )
            )
            
            val updatedAccounts = wallet.accounts.map {
                if (it.id == account.id) updatedAccount else it
            }
            saveWallet(wallet.copy(accounts = updatedAccounts))
            updatedAccount
        } catch (e: Exception) {
            android.util.Log.e("WalletRepository", "Failed to refresh account", e)
            null
        }
    }

    fun listWallets(): List<String> {
        val dir = File(context.filesDir, "wallets")
        if (!dir.exists()) return emptyList()
        return dir.listFiles { _, name -> name.startsWith("wallet_") && name.endsWith(".gaju") }
            ?.map { it.name.removePrefix("wallet_").removeSuffix(".gaju") }
            ?: emptyList()
    }

    private fun getWalletFile(walletId: String): File {
        val dir = File(context.filesDir, "wallets")
        if (!dir.exists()) dir.mkdirs()
        return File(dir, "wallet_$walletId.gaju")
    }
}
