/*
 * 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.models

import kotlinx.serialization.Serializable
import swiss.qpq.gajumobile.security.EncryptedEnvelope
import swiss.qpq.gajumaru.core.encoding.ApiEncoder
import swiss.qpq.gajumaru.core.formatting.GajuFormat
import java.math.BigInteger

@Serializable
data class Account(
    val id: String, // Unique identifier (e.g., UUID or derived from pubkey)
    val label: String,
    val publicKey: ByteArray,
    val privateKeyEnvelope: EncryptedEnvelope,
    val cachedBalance: CachedBalance? = null
) {
    /**
     * The canonical Gajumaru protocol ID (ak_...).
     */
    val gajuId: String
        get() = ApiEncoder.encode(ApiEncoder.Type.ACCOUNT_PUBKEY, publicKey)

    /**
     * A shortened version of the ID for tight UI layouts.
     */
    fun getShortId(): String {
        val full = gajuId
        return if (full.length <= 16) full else "${full.take(8)}...${full.takeLast(8)}"
    }

    /**
     * Renders the cached balance using the provided formatting rules.
     */
    fun formattedBalance(type: GajuFormat.Type, unit: GajuFormat.Unit): String {
        val bi = try { BigInteger(cachedBalance?.totalPucks ?: "0") } catch (_: Exception) { BigInteger.ZERO }
        return GajuFormat.amount(GajuFormat.standardSpec(type, unit), bi)
    }

    override fun equals(other: Any?): Boolean {
        if (this === other) return true
        if (javaClass != other?.javaClass) return false

        other as Account

        if (id != other.id) return false
        if (label != other.label) return false
        if (!publicKey.contentEquals(other.publicKey)) return false
        if (privateKeyEnvelope != other.privateKeyEnvelope) return false
        if (cachedBalance != other.cachedBalance) return false

        return true
    }

    override fun hashCode(): Int {
        var result = id.hashCode()
        result = 31 * result + label.hashCode()
        result = 31 * result + publicKey.contentHashCode()
        result = 31 * result + privateKeyEnvelope.hashCode()
        result = 31 * result + (cachedBalance?.hashCode() ?: 0)
        return result
    }
}

@Serializable
data class CachedBalance(
    val totalPucks: String,
    val chainId: String,
    val timestamp: Long
)
