package io.synor.wallet

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

/**
 * Network environment for wallet operations.
 */
@Serializable
enum class Network {
    @SerialName("mainnet") MAINNET,
    @SerialName("testnet") TESTNET,
    @SerialName("devnet") DEVNET
}

/**
 * Type of wallet to create.
 */
@Serializable
enum class WalletType {
    @SerialName("standard") STANDARD,
    @SerialName("multisig") MULTISIG,
    @SerialName("hardware") HARDWARE,
    @SerialName("stealth") STEALTH
}

/**
 * Transaction priority for fee estimation.
 */
@Serializable
enum class Priority {
    @SerialName("low") LOW,
    @SerialName("medium") MEDIUM,
    @SerialName("high") HIGH
}

/**
 * Configuration for the wallet client.
 */
data class WalletConfig(
    val apiKey: String,
    val endpoint: String = "https://wallet.synor.io/v1",
    val network: Network = Network.MAINNET,
    val timeout: Long = 30_000L,
    val retries: Int = 3,
    val debug: Boolean = false
) {
    class Builder(private val apiKey: String) {
        private var endpoint: String = "https://wallet.synor.io/v1"
        private var network: Network = Network.MAINNET
        private var timeout: Long = 30_000L
        private var retries: Int = 3
        private var debug: Boolean = false

        fun endpoint(endpoint: String) = apply { this.endpoint = endpoint }
        fun network(network: Network) = apply { this.network = network }
        fun timeout(timeout: Long) = apply { this.timeout = timeout }
        fun retries(retries: Int) = apply { this.retries = retries }
        fun debug(debug: Boolean) = apply { this.debug = debug }

        fun build() = WalletConfig(apiKey, endpoint, network, timeout, retries, debug)
    }

    companion object {
        fun builder(apiKey: String) = Builder(apiKey)
    }
}

/**
 * A Synor wallet with addresses and keys.
 */
@Serializable
data class Wallet(
    val id: String,
    val type: WalletType,
    val network: Network,
    val addresses: List<Address>,
    @SerialName("created_at") val createdAt: String
)

/**
 * A wallet address.
 */
@Serializable
data class Address(
    val address: String,
    val index: Int,
    @SerialName("is_change") val isChange: Boolean = false
)

/**
 * Stealth address for privacy transactions.
 */
@Serializable
data class StealthAddress(
    @SerialName("spend_public_key") val spendPublicKey: String,
    @SerialName("view_public_key") val viewPublicKey: String,
    @SerialName("one_time_address") val oneTimeAddress: String
)

/**
 * Result of wallet creation.
 */
@Serializable
data class CreateWalletResult(
    val wallet: Wallet,
    val mnemonic: String? = null
)

/**
 * Request to create a new wallet.
 */
@Serializable
internal data class CreateWalletRequest(
    val type: WalletType,
    val network: Network
)

/**
 * Request to import a wallet.
 */
@Serializable
internal data class ImportWalletRequest(
    val mnemonic: String,
    val passphrase: String?,
    val network: Network
)

/**
 * A blockchain transaction.
 */
@Serializable
data class Transaction(
    val inputs: List<TransactionInput>,
    val outputs: List<TransactionOutput>,
    val fee: Long? = null,
    val priority: Priority = Priority.MEDIUM
)

/**
 * Transaction input (UTXO reference).
 */
@Serializable
data class TransactionInput(
    val txid: String,
    val vout: Int,
    val amount: Long
)

/**
 * Transaction output.
 */
@Serializable
data class TransactionOutput(
    val address: String,
    val amount: Long
)

/**
 * A signed transaction ready for broadcast.
 */
@Serializable
data class SignedTransaction(
    val txid: String,
    val hex: String,
    val size: Int,
    val fee: Long
)

/**
 * Request to sign a transaction.
 */
@Serializable
internal data class SignTransactionRequest(
    @SerialName("wallet_id") val walletId: String,
    val transaction: Transaction
)

/**
 * Request to sign a message.
 */
@Serializable
internal data class SignMessageRequest(
    @SerialName("wallet_id") val walletId: String,
    val message: String,
    @SerialName("address_index") val addressIndex: Int
)

/**
 * A cryptographic signature.
 */
@Serializable
data class Signature(
    val signature: String,
    val address: String,
    @SerialName("recovery_id") val recoveryId: Int? = null
)

/**
 * Unspent transaction output.
 */
@Serializable
data class UTXO(
    val txid: String,
    val vout: Int,
    val amount: Long,
    val address: String,
    val confirmations: Int,
    @SerialName("script_pubkey") val scriptPubKey: String? = null
)

/**
 * Wallet balance information.
 */
@Serializable
data class Balance(
    val confirmed: Long,
    val unconfirmed: Long,
    val total: Long
)

/**
 * Exception thrown by wallet operations.
 */
class WalletException(
    message: String,
    val code: String? = null,
    val statusCode: Int? = null,
    cause: Throwable? = null
) : Exception(message, cause)
