package io.synor.wallet;

import java.util.List;

/** Network type. */
public enum Network {
    MAINNET("mainnet"),
    TESTNET("testnet");

    private final String value;
    Network(String value) { this.value = value; }
    public String getValue() { return value; }
}

/** Wallet type. */
public enum WalletType {
    STANDARD("standard"),
    MULTISIG("multisig"),
    STEALTH("stealth"),
    HARDWARE("hardware");

    private final String value;
    WalletType(String value) { this.value = value; }
    public String getValue() { return value; }
}

/** Transaction priority. */
public enum Priority {
    LOW("low"),
    MEDIUM("medium"),
    HIGH("high"),
    URGENT("urgent");

    private final String value;
    Priority(String value) { this.value = value; }
    public String getValue() { return value; }
}

/** Wallet configuration. */
class WalletConfig {
    private final String apiKey;
    private final String endpoint;
    private final Network network;
    private final long timeoutSeconds;
    private final boolean debug;

    private WalletConfig(Builder builder) {
        this.apiKey = builder.apiKey;
        this.endpoint = builder.endpoint;
        this.network = builder.network;
        this.timeoutSeconds = builder.timeoutSeconds;
        this.debug = builder.debug;
    }

    public String getApiKey() { return apiKey; }
    public String getEndpoint() { return endpoint; }
    public Network getNetwork() { return network; }
    public long getTimeoutSeconds() { return timeoutSeconds; }
    public boolean isDebug() { return debug; }

    public static Builder builder() { return new Builder(); }

    public static class Builder {
        private String apiKey;
        private String endpoint = "https://wallet.synor.cc/api/v1";
        private Network network = Network.MAINNET;
        private long timeoutSeconds = 30;
        private boolean debug = false;

        public Builder apiKey(String apiKey) { this.apiKey = apiKey; return this; }
        public Builder endpoint(String endpoint) { this.endpoint = endpoint; return this; }
        public Builder network(Network network) { this.network = network; return this; }
        public Builder timeoutSeconds(long seconds) { this.timeoutSeconds = seconds; return this; }
        public Builder debug(boolean debug) { this.debug = debug; return this; }
        public WalletConfig build() { return new WalletConfig(this); }
    }
}

/** Wallet instance. */
class Wallet {
    private String id;
    private String address;
    private String publicKey;
    private WalletType type;
    private long createdAt;

    public String getId() { return id; }
    public String getAddress() { return address; }
    public String getPublicKey() { return publicKey; }
    public WalletType getType() { return type; }
    public long getCreatedAt() { return createdAt; }
}

/** Create wallet result. */
class CreateWalletResult {
    private Wallet wallet;
    private String mnemonic;

    public Wallet getWallet() { return wallet; }
    public String getMnemonic() { return mnemonic; }
}

/** Transaction input. */
class TransactionInput {
    private String txid;
    private int vout;
    private String amount;
    private String scriptSig;

    public String getTxid() { return txid; }
    public int getVout() { return vout; }
    public String getAmount() { return amount; }
    public String getScriptSig() { return scriptSig; }
}

/** Transaction output. */
class TransactionOutput {
    private String address;
    private String amount;
    private String scriptPubKey;

    public String getAddress() { return address; }
    public String getAmount() { return amount; }
    public String getScriptPubKey() { return scriptPubKey; }
}

/** Transaction. */
class Transaction {
    private int version;
    private List<TransactionInput> inputs;
    private List<TransactionOutput> outputs;
    private int lockTime;
    private String fee;

    public int getVersion() { return version; }
    public List<TransactionInput> getInputs() { return inputs; }
    public List<TransactionOutput> getOutputs() { return outputs; }
    public int getLockTime() { return lockTime; }
    public String getFee() { return fee; }
}

/** Signed transaction. */
class SignedTransaction {
    private String raw;
    private String txid;
    private int size;
    private int weight;

    public String getRaw() { return raw; }
    public String getTxid() { return txid; }
    public int getSize() { return size; }
    public int getWeight() { return weight; }
}

/** Signed message. */
class SignedMessage {
    private String signature;
    private String publicKey;
    private String address;

    public String getSignature() { return signature; }
    public String getPublicKey() { return publicKey; }
    public String getAddress() { return address; }
}

/** UTXO. */
class UTXO {
    private String txid;
    private int vout;
    private String amount;
    private String address;
    private int confirmations;
    private String scriptPubKey;

    public String getTxid() { return txid; }
    public int getVout() { return vout; }
    public String getAmount() { return amount; }
    public String getAddress() { return address; }
    public int getConfirmations() { return confirmations; }
    public String getScriptPubKey() { return scriptPubKey; }
}

/** Balance. */
class Balance {
    private String confirmed;
    private String unconfirmed;
    private String total;

    public String getConfirmed() { return confirmed; }
    public String getUnconfirmed() { return unconfirmed; }
    public String getTotal() { return total; }
}

/** Token balance. */
class TokenBalance {
    private String token;
    private String symbol;
    private int decimals;
    private String balance;

    public String getToken() { return token; }
    public String getSymbol() { return symbol; }
    public int getDecimals() { return decimals; }
    public String getBalance() { return balance; }
}

/** Balance response. */
class BalanceResponse {
    private Balance nativeBalance;
    private List<TokenBalance> tokens;

    public Balance getNativeBalance() { return nativeBalance; }
    public List<TokenBalance> getTokens() { return tokens; }
}

/** Fee estimate. */
class FeeEstimate {
    private Priority priority;
    private String feeRate;
    private int estimatedBlocks;

    public Priority getPriority() { return priority; }
    public String getFeeRate() { return feeRate; }
    public int getEstimatedBlocks() { return estimatedBlocks; }
}

/** Wallet exception. */
class WalletException extends RuntimeException {
    private final int statusCode;
    private final String code;

    public WalletException(String message, int statusCode, String code) {
        super(message);
        this.statusCode = statusCode;
        this.code = code;
    }

    public int getStatusCode() { return statusCode; }
    public String getCode() { return code; }
}
