package org.bitcoindevkit

/**
 * The cryptocurrency to act on.
 *
 * @sample org.bitcoindevkit.networkSample
 */
enum class Network {
    /** Bitcoin's mainnet. */
    BITCOIN,

    /** Bitcoin’s testnet. */
    TESTNET,

    /** Bitcoin’s signet. */
    SIGNET,

    /** Bitcoin’s regtest. */
    REGTEST,
}

/**
 * A derived address and the index it was found at.
 *
 * @property index Child index of this address.
 * @property address Address.
 * @property keychain Type of keychain.
 *
 * @sample org.bitcoindevkit.addressInfoSample
 */
data class AddressInfo (
    var index: UInt,
    var address: Address,
    var keychain: KeychainKind
)

/**
 * The address index selection strategy to use to derive an address from the wallet’s external descriptor.
 *
 * If you’re unsure which one to use, use `AddressIndex.New`.
 *
 * @sample org.bitcoindevkit.addressIndexSample
 */
sealed class AddressIndex {
    /** Return a new address after incrementing the current descriptor index. */
    object New: AddressIndex(),

    /**
     * Return the address for the current descriptor index if it has not been used in a received transaction.
     * Otherwise return a new address as with `AddressIndex.NEW`. Use with caution, if the wallet
     * has not yet detected an address has been used it could return an already used address.
     * This function is primarily meant for situations where the caller is untrusted;
     * for example when deriving donation addresses on-demand for a public web page.
     */
    object LastUnused: AddressIndex(),

    /**
     * Return the address for a specific descriptor index. Does not change the current descriptor
     * index used by [AddressIndex.New] and [AddressIndex.LastUsed].
     * Use with caution, if an index is given that is less than the current descriptor index
     * then the returned address may have already been used.
     */
    data class Peek(val index: UInt): AddressIndex(),

    /**
     * Return the address for a specific descriptor index and reset the current descriptor index
     * used by [AddressIndex.New] and [AddressIndex.LastUsed] to this value.
     * Use with caution, if an index is given that is less than the current descriptor index
     * then the returned address and subsequent addresses returned by calls to [AddressIndex.New]
     * and [AddressIndex.LastUsed] may have already been used. Also if the index is reset to a
     * value earlier than the [Blockchain] stopGap (default is 20) then a
     * larger stopGap should be used to monitor for all possibly used addresses.
     */
    data class Reset(val index: UInt): AddressIndex()
}

/**
 * Balance differentiated in various categories.
 *
 * @property immature All coinbase outputs not yet matured.
 * @property trustedPending Unconfirmed UTXOs generated by a wallet tx.
 * @property untrustedPending Unconfirmed UTXOs received from an external wallet.
 * @property confirmed Confirmed and immediately spendable balance.
 * @property spendable The sum of trustedPending and confirmed coins.
 * @property total The whole balance visible to the wallet.
 *
 * @sample org.bitcoindevkit.balanceSample
 */
data class Balance (
    var immature: ULong,
    var trustedPending: ULong,
    var untrustedPending: ULong,
    var confirmed: ULong,
    var spendable: ULong,
    var total: ULong
)

/**
 * Type that can contain any of the database configurations defined by the library.
 *
 * @sample org.bitcoindevkit.memoryDatabaseConfigSample
 * @sample org.bitcoindevkit.sqliteDatabaseConfigSample
 */
sealed class DatabaseConfig {
    /** Configuration for an in-memory database. */
    object Memory : DatabaseConfig()

    /** Configuration for a Sled database. */
    data class Sled(val config: SledDbConfiguration) : DatabaseConfig()

    /** Configuration for a SQLite database. */
    data class Sqlite(val config: SqliteDbConfiguration) : DatabaseConfig()
}

/**
 * Configuration type for a SQLite database.
 *
 * @property path Main directory of the DB.
 *
 * @sample org.bitcoindevkit.sqliteDatabaseConfigSample
 */
data class SqliteDbConfiguration(
    var path: String,
)

/**
 * Configuration type for a SledDB database.
 *
 * @property path Main directory of the DB.
 * @property treeName Name of the database tree, a separated namespace for the data.
 */
data class SledDbConfiguration(
    var path: String,
    var treeName: String,
)

/**
 * Configuration for an Electrum blockchain.
 *
 * @property url URL of the Electrum server (such as ElectrumX, Esplora, BWT) may start with `ssl://` or `tcp://` and include a port, e.g. `ssl://electrum.blockstream.info:60002`.
 * @property socks5 URL of the socks5 proxy server or a Tor service.
 * @property retry Request retry count.
 * @property timeout Request timeout (seconds).
 * @property stopGap Stop searching addresses for transactions after finding an unused gap of this length.
 * @property validateDomain Validate the domain when using SSL.
 *
 * @sample org.bitcoindevkit.electrumBlockchainConfigSample
 */
data class ElectrumConfig(
    var url: String,
    var socks5: String?,
    var retry: UByte,
    var timeout: UByte?,
    var stopGap: ULong,
    var validateDomain: Boolean
)

/**
 * Configuration for an Esplora blockchain.
 *
 * @property baseUrl Base URL of the esplora service, e.g. `https://blockstream.info/api/`.
 * @property proxy Optional URL of the proxy to use to make requests to the Esplora server.
 * @property concurrency Number of parallel requests sent to the esplora service (default: 4).
 * @property stopGap Stop searching addresses for transactions after finding an unused gap of this length.
 * @property timeout Socket timeout.
 *
 * @sample org.bitcoindevkit.esploraBlockchainConfigSample
 */
data class EsploraConfig(
    var baseUrl: String,
    var proxy: String?,
    var concurrency: UByte?,
    var stopGap: ULong,
    var timeout: ULong?
)

/**
 * Authentication mechanism for RPC connection to full node.
 */
sealed class Auth {
    /** No authentication */
    object None: Auth()

    /** Authentication with username and password, usually [Auth.Cookie] should be preferred */
    data class UserPass(val username: String, val password: String): Auth()

    /** Authentication with a cookie file */
    data class Cookie(val file: String): Auth()
}

/**
 * Sync parameters for Bitcoin Core RPC.
 *
 * In general, BDK tries to sync `scriptPubKey`s cached in `Database` with
 * `scriptPubKey`s imported in the Bitcoin Core Wallet. These parameters are used for determining
 * how the `importdescriptors` RPC calls are to be made.
 *
 * @property startScriptCount The minimum number of scripts to scan for on initial sync.
 * @property startTime Time in unix seconds in which initial sync will start scanning from (0 to start from genesis).
 * @property forceStartTime Forces every sync to use `start_time` as import timestamp.
 * @property pollRateSec RPC poll rate (in seconds) to get state updates.
 */
data class RcpSyncParams(
    val startScriptCount: ULong,
    val startTime: Ulong,
    val forceStartTime: Boolean,
    val pollRateSec: ULong,
)

/**
 * RpcBlockchain configuration options
 *
 * @property url The bitcoin node url.
 * @property auth The bicoin node authentication mechanism.
 * @property network The network we are using (it will be checked the bitcoin node network matches this).
 * @property walletName The wallet name in the bitcoin node.
 * @property syncParams Sync parameters.
 */
data class RpcConfig(
    val url: String,
    val auth: Auth,
    val network: Network,
    val walletName: String,
    val syncParams: RcpSyncParams?,
)

/**
 * Type that can contain any of the blockchain configurations defined by the library.
 *
 * @sample org.bitcoindevkit.electrumBlockchainConfigSample
 */
sealed class BlockchainConfig {
    /** Electrum client. */
    data class Electrum(val config: ElectrumConfig) : BlockchainConfig()

    /** Esplora client. */
    data class Esplora(val config: EsploraConfig) : BlockchainConfig()

    /** Bitcoin Core RPC client. */
    data class Rpc(val config: RpcConfig) : BlockchainConfig()
}

/**
 * A wallet transaction.
 *
 * @property fee Fee value (sats) if available. The availability of the fee depends on the backend. It’s never None with an Electrum server backend, but it could be None with a Bitcoin RPC node without txindex that receive funds while offline.
 * @property received Received value (sats) Sum of owned outputs of this transaction.
 * @property sent Sent value (sats) Sum of owned inputs of this transaction.
 * @property txid Transaction id.
 * @property confirmationTime If the transaction is confirmed, [BlockTime] contains height and timestamp of the block containing the transaction. This property is null for unconfirmed transactions.
 */
data class TransactionDetails (
    var transaction?: Transaction,
    var fee: ULong?,
    var received: ULong,
    var sent: ULong,
    var txid: String,
    var confirmationTime: BlockTime?
)

/**
 * A blockchain backend.
 *
 * @constructor Create the new blockchain client.
 *
 * @param config The blockchain configuration required.
 *
 * @sample org.bitcoindevkit.blockchainSample
 */
class Blockchain(
    config: BlockchainConfig
) {
    /** Broadcast a transaction. */
    fun broadcast(transaction: Transaction) {}

    /** Estimate the fee rate required to confirm a transaction in a given target of blocks. */
    fun estimateFee(target: ULong): FeeRate {}

    /** Get the current height of the blockchain. */
    fun getHeight(): UInt {}

    /** Get the block hash of a given block. */
    fun getBlockHash(height: UInt): String {}
}

/**
 * A bitcoin transaction.
 *
 * @constructor Build a new Bitcoin Transaction.
 *
 * @param transactionBytes The transaction bytes, bitcoin consensus encoded.
 */
class Transaction(transactionBytes: List<UByte>) {
    /** Computes the txid. */
    fun txid(): String {}

    /**
     * Returns the "weight" of this transaction, as defined by BIP141.
     *
     * For transactions with an empty witness, this is simply the consensus-serialized size times four.
     * For transactions with a witness, this is the non-witness consensus-serialized size multiplied by three
     * plus the with-witness consensus-serialized size.
     */
    fun weight(): ULong {}

    /** Returns the regular byte-wise consensus-serialized size of this transaction. */
    fun size(): ULong {}

    /**
     * Returns the "virtual size" (vsize) of this transaction.
     *
     * Will be ceil(weight / 4.0). Note this implements the virtual size as per BIP141, which is different to
     * what is implemented in Bitcoin Core. The computation should be the same for any remotely sane transaction.
     */
    fun vsize(): ULong {}

    /** Return the transaction bytes, bitcoin consensus encoded. */
    fun serialize(): List<UByte> {}

    /** Is this a coin base transaction? */
    fun isCoinBase(): Boolean {}

    /**
     * Returns true if the transaction itself opted in to be BIP-125-replaceable (RBF).
     * This does not cover the case where a transaction becomes replaceable due to ancestors being RBF.
     */
    fun isExplicitlyRbf(): Boolean {}

    /** Returns true if this transactions nLockTime is enabled (BIP-65). */
    fun isLockTimeEnabled(): Boolean {}

    /** The protocol version, is currently expected to be 1 or 2 (BIP 68). */
    fun version(): Int {}

    /**
     * Block height or timestamp. Transaction cannot be included in a block until this height/time.
     * Relevant BIPs
     *     BIP-65 OP_CHECKLOCKTIMEVERIFY
     *     BIP-113 Median time-past as endpoint for lock-time calculations
     */
    fun lockTime(): UInt {}

    /** List of transaction inputs. */
    fun input(): List<TxIn> {}

    /** List of transaction outputs. */
    fun output(): List<TxOut> {}
}

/**
 * A partially signed bitcoin transaction.
 *
 * @constructor Build a new Partially Signed Bitcoin Transaction.
 *
 * @param psbtBase64 The PSBT in base64 format.
 */
class PartiallySignedTransaction(psbtBase64: String) {
    /** Return the PSBT in string format, using a base64 encoding. */
    fun serialize(): String {}

    /** Get the txid of the PSBT. */
    fun txid(): String {}

    /** Extract the transaction. */
    fun extractTx(): Transaction {}

    /**
     * Combines this PartiallySignedTransaction with another PSBT as described by BIP 174.
     * In accordance with BIP 174 this function is commutative i.e., `A.combine(B) == B.combine(A)`
     */
    fun combine(other: PartiallySignedTransaction): PartiallySignedTransaction

    /** Serialize the PSBT data structure as a String of JSON. */
    fun jsonSerialize(): String
}

/**
 * A reference to a transaction output.
 *
 * @property txid The referenced transaction’s txid.
 * @property vout The index of the referenced output in its transaction’s vout.
 */
data class OutPoint (
    var txid: String,
    var vout: UInt
)

/**
 * A transaction output, which defines new coins to be created from old ones.
 *
 * @property value The value of the output, in satoshis.
 * @property scriptPubkey The script which must be satisfied for the output to be spent.
 */
data class TxOut (
    var value: ULong,
    var scriptPubkey: Script
)

/**
 * Bitcoin transaction input.
 *
 * It contains the location of the previous transaction’s output, that it spends and set of scripts that satisfy its spending conditions.
 *
 * @property previousOutput The reference to the previous output that is being used an an input.
 * @property scriptSig The script which pushes values on the stack which will cause the referenced output’s script to be accepted.
 * @property sequence The sequence number, which suggests to miners which of two conflicting transactions should be preferred, or 0xFFFFFFFF to ignore this feature. This is generally never used since the miner behaviour cannot be enforced.
 * @property witness Witness data: an array of byte-arrays. Note that this field is not (de)serialized with the rest of the TxIn in Encodable/Decodable, as it is (de)serialized at the end of the full Transaction. It is (de)serialized with the rest of the TxIn in other (de)serialization routines.
 *
 */
data class TxIn (
    var previousOutput: OutPoint,
    var scriptSig: Script,
    var sequence: UInt,
    var witness: List<List<UByte>>
)

/**
 * An unspent output owned by a [Wallet].
 *
 * @property outpoint Reference to a transaction output.
 * @property txout Transaction output.
 * @property keychain Type of keychain.
 * @property isSpent Whether this UTXO is spent or not.
 */
data class LocalUtxo (
    var outpoint: OutPoint,
    var txout: TxOut,
    var keychain: KeychainKind,
    var isSpent: Boolean
)

/**
 * Types of keychains.
 */
enum class KeychainKind {
    /** External. */
    EXTERNAL,

    /** Internal, usually used for change outputs. */
    INTERNAL,
}

/**
 * Block height and timestamp of a block.
 *
 * @property height Confirmation block height.
 * @property timestamp Confirmation block timestamp.
 */
data class BlockTime (
    var height: UInt,
    var timestamp: ULong,
)

/**
 * A Bitcoin wallet.
 * The Wallet acts as a way of coherently interfacing with output descriptors and related transactions. Its main components are:
 * 1. Output descriptors from which it can derive addresses.
 * 2. A Database where it tracks transactions and utxos related to the descriptors.
 * 3. Signers that can contribute signatures to addresses instantiated from the descriptors.
 *
 * @constructor Create a BDK wallet.
 *
 * @param descriptor The main (or "external") descriptor.
 * @param changeDescriptor? The change (or "internal") descriptor.
 * @param network The network to act on.
 * @param databaseConfig The database configuration.
 *
 * @sample org.bitcoindevkit.walletSample
 */
class Wallet(
    descriptor: Descriptor,
    changeDescriptor: Descriptor?,
    network: Network,
    databaseConfig: DatabaseConfig,
) {
    /**
     * Return a derived address using the external descriptor, see [AddressIndex] for available address index
     * selection strategies. If none of the keys in the descriptor are derivable (i.e. the descriptor does not end
     * with a * character) then the same address will always be returned for any [AddressIndex].
     */
    fun getAddress(addressIndex: AddressIndex): AddressInfo {}

    /**
     * Return a derived address using the internal (change) descriptor.
     * If the wallet doesn't have an internal descriptor it will use the external descriptor.
     * See [AddressIndex] for available address index selection strategies. If none of the keys
     * in the descriptor are derivable (i.e. does not end with /\*) then the same address will always
     * be returned for any [AddressIndex].
     */
    fun getInternalAddress(addressIndex: AddressIndex): AddressInfo {}

    /** Return whether or not a script is part of this wallet (either internal or external). */
    fun isMine(script: Script): Boolean {}

    /** Return the wallet's balance, across different categories. See [Balance] for the categories. Note that this method only operates on the internal database, which first needs to be [Wallet.sync] manually. */
    fun getBalance(): Balance {}

    /**
     * Sign a transaction with all the wallet's signers, in the order specified by every signer's
     * `SignerOrdering`.
     *
     * The `SignOptions` can be used to tweak the behavior of the software signers, and the way
     * the transaction is finalized at the end. Note that it can't be guaranteed that *every*
     * signers will follow the options, but the "software signers" (WIF keys and `xprv`) defined
     * in this library will.
     *
     * @param psbt PSBT to be signed
     * @param signOptions signing options
     * @return true if the PSBT was finalized, or false otherwise
     */
    fun sign(psbt: PartiallySignedTransaction, signOptions: SignOptions?): Boolean {}

    /** Return the list of transactions made and received by the wallet. Note that this method only operate on the internal database, which first needs to be [Wallet.sync] manually. */
    fun listTransactions(includeRaw: Boolean): List<TransactionDetails> {}

    /** Get the Bitcoin network the wallet is using. */
    fun network(): Network {}

    /** Sync the internal database with the blockchain. */
    fun sync(blockchain: Blockchain, progress: Progress?) {}

    /** Return the list of unspent outputs of this wallet. Note that this method only operates on the internal database, which first needs to be [Wallet.sync] manually. */
    fun listUnspent(): List<LocalUtxo> {}
}

/**
 * Class that logs at level INFO every update received (if any).
 */
class Progress {
    /** Send a new progress update. The progress value should be in the range 0.0 - 100.0, and the message value is an optional text message that can be displayed to the user. */
    fun update(progress: Float, message: String?) {}
}

/**
 * A transaction builder.
 *
 * After creating the TxBuilder, you set options on it until finally calling `.finish` to consume the builder and generate the transaction.
 *
 * Each method on the TxBuilder returns an instance of a new TxBuilder with the option set/added.
 *
 * @sample org.bitcoindevkit.txBuilderResultSample1
 * @sample org.bitcoindevkit.txBuilderResultSample2
 */
class TxBuilder() {
    /** Add data as an output using OP_RETURN. */
    fun addData(data: List<UByte>): TxBuilder {}

    /** Add a recipient to the internal list. */
    fun addRecipient(script: Script, amount: ULong): TxBuilder {}

    /** Set the list of recipients by providing a list of [ScriptAmount]. */
    fun setRecipients(recipients: List<ScriptAmount>): TxBuilder {}

    /** Add a utxo to the internal list of unspendable utxos. It’s important to note that the "must-be-spent" utxos added with [TxBuilder.addUtxo] have priority over this. See the Rust docs of the two linked methods for more details. */
    fun addUnspendable(unspendable: OutPoint): TxBuilder {}

    /** Add an outpoint to the internal list of UTXOs that must be spent. These have priority over the "unspendable" utxos, meaning that if a utxo is present both in the "utxos" and the "unspendable" list, it will be spent. */
    fun addUtxo(outpoint: OutPoint): TxBuilder {}

    /**
     * Add the list of outpoints to the internal list of UTXOs that must be spent. If an error
     * occurs while adding any of the UTXOs then none of them are added and the error is returned.
     * These have priority over the "unspendable" utxos, meaning that if a utxo is present both
     * in the "utxos" and the "unspendable" list, it will be spent.
     */
    fun addUtxos(outpoints: List<OutPoint>): TxBuilder {}

    /** Do not spend change outputs. This effectively adds all the change outputs to the "unspendable" list. See [TxBuilder.unspendable]. */
    fun doNotSpendChange(): TxBuilder {}

    /** Only spend utxos added by [add_utxo]. The wallet will not add additional utxos to the transaction even if they are needed to make the transaction valid. */
    fun manuallySelectedOnly(): TxBuilder {}

    /** Only spend change outputs. This effectively adds all the non-change outputs to the "unspendable" list. See [TxBuilder.unspendable]. */
    fun onlySpendChange(): TxBuilder {}

    /**
     * Replace the internal list of unspendable utxos with a new list. It’s important to note that the "must-be-spent" utxos
     * added with [TxBuilder.addUtxo] have priority over these. See the Rust docs of the two linked methods for more details.
     */
    fun unspendable(unspendable: List<OutPoint>): TxBuilder {}

    /** Set a custom fee rate. */
    fun feeRate(satPerVbyte: Float): TxBuilder {}

    /** Set an absolute fee. */
    fun feeAbsolute(feeAmount: ULong): TxBuilder {}

    /** Spend all the available inputs. This respects filters like [TxBuilder.unspendable] and the change policy. */
    fun drainWallet(): TxBuilder {}

    /**
     * Sets the address to drain excess coins to. Usually, when there are excess coins they are
     * sent to a change address generated by the wallet. This option replaces the usual change address
     * with an arbitrary ScriptPubKey of your choosing. Just as with a change output, if the
     * drain output is not needed (the excess coins are too small) it will not be included in the resulting
     * transaction. The only difference is that it is valid to use [drainTo] without setting any ordinary recipients
     * with [addRecipient] (but it is perfectly fine to add recipients as well). If you choose not to set any
     * recipients, you should either provide the utxos that the transaction should spend via [addUtxos], or set
     * [drainWallet] to spend all of them. When bumping the fees of a transaction made with this option,
     * you probably want to use [BumpFeeTxBuilder.allowShrinking] to allow this output to be reduced to pay for the extra fees.
     */
    fun drainTo(script: Script): TxBuilder {}

    /** Enable signaling RBF. This will use the default `nsequence` value of `0xFFFFFFFD`. */
    fun enableRbf(): TxBuilder {}

    /**
     * Enable signaling RBF with a specific nSequence value. This can cause conflicts if the wallet's descriptors
     * contain an "older" (OP_CSV) operator and the given `nsequence` is lower than the CSV value. If the `nsequence`
     * is higher than `0xFFFFFFFD` an error will be thrown, since it would not be a valid nSequence to signal RBF.
     */
    fun enableRbfWithSequence(nsequence: UInt): TxBuilder {}

    /** Finish building the transaction. Returns a [TxBuilderResult]. */
    fun finish(wallet: Wallet): TxBuilderResult {}
}

/**
 * Options for a software signer.
 *
 * Adjust the behavior of our software signers and the way a transaction is finalized.
 *
 * @property trustWitnessUtxo Whether the signer should trust the `witness_utxo`, if the `non_witness_utxo` hasn't been provided. Defaults to `false`.
 * @property assumeHeight Whether the wallet should assume a specific height has been reached when trying to finalize a transaction.
 * @property allowAllSighashes Whether the signer should use the sighash_type set in the PSBT when signing, no matter what its value is. Defaults to `false`.
 * @property removePartialSigs Whether to remove partial signatures from the PSBT inputs while finalizing PSBT. Defaults to `true`.
 * @property tryFinalize Whether to try finalizing the PSBT after the inputs are signed. Defaults to `true`.
 * @property signWithTapInternalKey Whether we should try to sign a taproot transaction with the taproot internal key or not. This option is ignored if we're signing a non-taproot PSBT. Defaults to `true`.
 * @property allowGrinding Whether we should grind ECDSA signature to ensure signing with low r or not. Defaults to `true`.
 */
data class SignOptions (
    var trustWitnessUtxo: Boolean,
    var assumeHeight: UInt?,
    var allowAllSighashes: Boolean,
    var removePartialSigs: Boolean,
    var tryFinalize: Boolean,
    var signWithTapInternalKey: Boolean,
    var allowGrinding: Boolean
)

/**
 * A object holding a ScriptPubKey and an amount.
 *
 * @property script The ScriptPubKey.
 * @property amount The amount.
 */
data class ScriptAmount (
    var script: Script,
    var amount: ULong
)

/**
 * The BumpFeeTxBuilder is used to bump the fee on a transaction that has been broadcast and has its RBF flag set to true.
 */
class BumpFeeTxBuilder() {
    /**
     * Explicitly tells the wallet that it is allowed to reduce the amount of the output matching this scriptPubKey
     * in order to bump the transaction fee. Without specifying this the wallet will attempt to find a change output
     * to shrink instead. Note that the output may shrink to below the dust limit and therefore be removed. If it is
     * preserved then it is currently not guaranteed to be in the same position as it was originally. Returns an error
     * if scriptPubkey can’t be found among the recipients of the transaction we are bumping.
     */
    fun allowShrinking(address: String): BumpFeeTxBuilder {}

    /** Enable signaling RBF. This will use the default `nsequence` value of `0xFFFFFFFD`. */
    fun enableRbf(): BumpFeeTxBuilder {}

    /**
     * Enable signaling RBF with a specific nSequence value. This can cause conflicts if the wallet's descriptors
     * contain an "older" (OP_CSV) operator and the given `nsequence` is lower than the CSV value. If the `nsequence`
     * is higher than `0xFFFFFFFD` an error will be thrown, since it would not be a valid nSequence to signal RBF.
     */
    fun enableRbfWithSequence(nsequence: UInt): BumpFeeTxBuilder {}

    /** Finish building the transaction. Returns a [TxBuilderResult]. */
    fun finish(wallet: Wallet): TxBuilderResult {}
}

/**
 * A BIP-32 derivation path.
 *
 * @param path The derivation path. Must start with `m`. Use this type to derive or extend a [DescriptorSecretKey]
 * or [DescriptorPublicKey].
 */
class DerivationPath(path: String) {}

/**
 * An extended secret key.
 *
 * @param network The network this DescriptorSecretKey is to be used on.
 * @param mnemonic The mnemonic.
 * @param password The optional passphrase that can be provided as per BIP-39.
 *
 * @sample org.bitcoindevkit.descriptorSecretKeyDeriveSample
 * @sample org.bitcoindevkit.descriptorSecretKeyExtendSample
 */
class DescriptorSecretKey(network: Network, mnemonic: Mnemonic, password: String?) {
    /** Build a DescriptorSecretKey from a String */
    fun fromString(secretKey: String): DescriptorSecretKey {}

    /** Derive a private descriptor at a given path. */
    fun derive(path: DerivationPath): DescriptorSecretKey {}

    /** Extend the private descriptor with a custom path. */
    fun extend(path: DerivationPath): DescriptorSecretKey {}

    /** Return the public version of the descriptor. */
    fun asPublic(): DescriptorPublicKey {}

    /** Return the raw private key as bytes. */
    fun secretBytes(): List<UByte>

    /** Return the private descriptor as a string. */
    fun asString(): String {}
}

/**
 * An extended public key.
 *
 * @param network The network this DescriptorPublicKey is to be used on.
 * @param mnemonic The mnemonic.
 * @param password The optional passphrase that can be provided as per BIP-39.
 */
class DescriptorPublicKey(network: Network, mnemonic: String, password: String?) {
    /** Build a DescriptorPublicKey from a String */
    fun fromString(publicKey: String): DescriptorPublicKey {}

    /** Derive a public descriptor at a given path. */
    fun derive(path: DerivationPath): DescriptorPublicKey

    /** Extend the public descriptor with a custom path. */
    fun extend(path: DerivationPath): DescriptorPublicKey

    /** Return the public descriptor as a string. */
    fun asString(): String
}

/**
 * A output descriptor.
 *
 * @param descriptor The descriptor in string format.
 * @param network The network this descriptor is to be used on.
 *
 * @sample org.bitcoindevkit.descriptorTemplates1
 * @sample org.bitcoindevkit.descriptorTemplates2
 */
class Descriptor(descriptor: String, network: Network) {
    /**
     * BIP44 template. Expands to pkh(key/44'/{0,1}'/0'/{0,1}/\*)
     * Since there are hardened derivation steps, this template requires a private derivable key (generally a xprv/tprv).
     */
    fun newBip44(secretKey: DescriptorSecretKey, keychain: KeychainKind, network: Network) {}

    /**
     * BIP44 public template. Expands to pkh(key/{0,1}/\*)
     * This assumes that the key used has already been derived with m/44'/0'/0' for Mainnet or m/44'/1'/0' for Testnet.
     * This template requires the parent fingerprint to populate correctly the metadata of PSBTs.
     */
    fun newBip44Public(publicKey: DescriptorPublicKey, fingerprint: String, keychain: KeychainKind, network: Network) {}

    /**
     * BIP49 template. Expands to sh(wpkh(key/49'/{0,1}'/0'/{0,1}/\*))
     * Since there are hardened derivation steps, this template requires a private derivable key (generally a xprv/tprv).
     */
    fun newBip49(secretKey: DescriptorSecretKey, keychain: KeychainKind, network: Network) {}

    /**
     * BIP49 public template. Expands to sh(wpkh(key/{0,1}/\*))
     * This assumes that the key used has already been derived with m/49'/0'/0' for Mainnet or m/49'/1'/0' for Testnet.
     * This template requires the parent fingerprint to populate correctly the metadata of PSBTs.
     */
    fun newBip49Public(publicKey: DescriptorPublicKey, fingerprint: String, keychain: KeychainKind, network: Network) {}

    /**
     * BIP84 template. Expands to wpkh(key/84'/{0,1}'/0'/{0,1}/\*)
     * Since there are hardened derivation steps, this template requires a private derivable key (generally a xprv/tprv).
     */
    fun newBip84(secretKey: DescriptorSecretKey, keychain: KeychainKind, network: Network) {}

    /**
     * BIP84 public template. Expands to wpkh(key/{0,1}/\*)
     * This assumes that the key used has already been derived with m/84'/0'/0' for Mainnet or m/84'/1'/0' for Testnet.
     * This template requires the parent fingerprint to populate correctly the metadata of PSBTs.
     */
    fun newBip84Public(publicKey: DescriptorPublicKey, fingerprint: String, keychain: KeychainKind, network: Network) {}

    /** Return the public version of the output descriptor. */
    fun asString(): String {}

    /** Return the private version of the output descriptor if available, otherwise return the public version. */
    fun asStringPrivate(): String {}
}

/**
 * An enum describing entropy length (aka word count) in the mnemonic.
 */
enum class WordCount {
    /** 12 words mnemonic (128 bits entropy). */
    WORDS12,

    /** 15 words mnemonic (160 bits entropy). */
    WORDS15,

    /** 18 words mnemonic (192 bits entropy). */
    WORDS18,

    /** 21 words mnemonic (224 bits entropy). */
    WORDS21,

    /** 24 words mnemonic (256 bits entropy). */
    WORDS24,
}

/**
 * The value returned from calling the `.finish()` method on the [TxBuilder] or [BumpFeeTxBuilder].
 *
 * @property psbt The PSBT
 * @property transactionDetails The transaction details.
 *
 * @sample org.bitcoindevkit.txBuilderResultSample1
 * @sample org.bitcoindevkit.txBuilderResultSample2
 */
data class TxBuilderResult (
    var psbt: PartiallySignedTransaction,
    var transactionDetails: TransactionDetails
)

/**
 * A bitcoin script.
 */
class Script(rawOutputScript: List<UByte>) {
    /** Return the script as bytes. */
    fun toBytes(): List<UByte> {}
}

/**
 * A bitcoin address.
 *
 * @param address The address in string format.
 */
class Address(address: String) {
    /** Construct an [`Address`] from an output script. */
    fun fromScript(script: Script, network: Network): Address {}

    /** Return the Payload */
    fun payload(): Payload

    /** Return the Network. */
    fun network(): Network

    /** Return the ScriptPubKey. */
    fun scriptPubkey(): Script

    /**
     * Creates a URI string bitcoin:address optimized to be encoded in QR codes.
     *
     * If the address is bech32, both the schema and the address become uppercase. If the address is base58, the schema is lowercase and the address is left mixed case.
     *
     * Quoting BIP 173 "inside QR codes uppercase SHOULD be used, as those permit the use of alphanumeric mode, which is 45% more compact than the normal byte mode."
     */
    fun toQrUri(): String

    /** Return the address as a string. */
    fun asString(): String
}}

/**
 * The method used to produce an address.
 */
sealed class Payload {
    /** P2PKH address. */
    data class PubkeyHash(
        val pubkeyHash: List<UByte>
    ) : Payload()

    /** P2SH address. */
    data class ScriptHash(
        val scriptHash: List<UByte>
    ) : Payload()

    /** Segwit address. */
    data class WitnessProgram(
        val version: WitnessVersion,
        val program: List<UByte>
    ) : Payload()
}

/**
 * Version of the witness program.
 *
 * Helps limit possible versions of the witness according to the specification. If a plain u8 type
 * was used instead it would mean that the version may be > 16, which would be incorrect.
 * First byte of scriptPubkey in transaction output for transactions starting with opcodes ranging
 * from 0 to 16 (inclusive).
 */
enum class WitnessVersion {
    V0, V1, V2, V3, V4, V5, V6, V7, V8, V9, V10, V11, V12, V13, V14, V15, V16
}

/**
 * Mnemonic phrases are a human-readable version of the private keys. Supported number of words are 12, 15, 18, 21 and 24.
 *
 * @constructor Generates Mnemonic with a random entropy.
 * @param mnemonic The mnemonic as a string of space-separated words.
 *
 * @sample org.bitcoindevkit.mnemonicSample
 */
class Mnemonic(mnemonic: String) {
    /* Returns Mnemonic as string */
    fun asString(): String

    /* Parse a Mnemonic from a given string. */
    fun fromString(): Mnemonic

    /*
     * Create a new Mnemonic in the specified language from the given entropy. Entropy must be a
     * multiple of 32 bits (4 bytes) and 128-256 bits in length.
     */
    fun fromEntropy(): Mnemonic
}
