use bitcoin::address::NetworkUnchecked;
use clap::Subcommand;
use fedimint_core::BitcoinAmountOrAll;
use fedimint_core::util::SafeUrl;
use fedimint_gateway_client::{get_ln_onchain_address, send_onchain};
use fedimint_gateway_common::SendOnchainRequest;
use fedimint_ln_common::client::GatewayApi;

use crate::{CliOutput, CliOutputResult};

/// Onchain management commands for sending or receiving funds from the
/// gateway's onchain wallet.
#[derive(Subcommand)]
pub enum OnchainCommands {
    /// Get a Bitcoin address from the gateway's lightning node's onchain
    /// wallet.
    Address,
    /// Send funds from the lightning node's on-chain wallet to a specified
    /// address.
    Send {
        /// The address to withdraw funds to.
        #[clap(long)]
        address: bitcoin::Address<NetworkUnchecked>,

        /// The amount to withdraw.
        /// Can be "all" to withdraw all funds, an amount + unit (e.g. "1000
        /// sats"), or a raw amount (e.g. "1000") which is denominated in
        /// millisats.
        #[clap(long)]
        amount: BitcoinAmountOrAll,

        /// The fee rate to use in satoshis per vbyte.
        #[clap(long)]
        fee_rate_sats_per_vbyte: u64,
    },
}

impl OnchainCommands {
    pub async fn handle(self, client: &GatewayApi, base_url: &SafeUrl) -> CliOutputResult {
        match self {
            Self::Address => {
                let response = get_ln_onchain_address(client, base_url)
                    .await?
                    .assume_checked();
                Ok(CliOutput::OnchainAddress {
                    address: response.to_string(),
                })
            }
            Self::Send {
                address,
                amount,
                fee_rate_sats_per_vbyte,
            } => {
                let txid = send_onchain(
                    client,
                    base_url,
                    SendOnchainRequest {
                        address,
                        amount,
                        fee_rate_sats_per_vbyte,
                    },
                )
                .await?;
                Ok(CliOutput::SendOnchainTxid { txid })
            }
        }
    }
}
