use super::RpcHandler;
use anyhow::{Context, Result};
use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize)]
struct LndInfo {
    alias: String,
    num_active_channels: u32,
    num_peers: u32,
    synced_to_chain: bool,
    block_height: u64,
    balance_sats: i64,
    channel_balance_sats: i64,
    pending_open_balance: i64,
}

#[derive(Debug, Deserialize)]
struct LndGetInfoResponse {
    alias: Option<String>,
    num_active_channels: Option<u32>,
    num_peers: Option<u32>,
    synced_to_chain: Option<bool>,
    block_height: Option<u64>,
}

#[derive(Debug, Deserialize)]
struct LndChannelBalanceResponse {
    local_balance: Option<LndAmount>,
    pending_open_local_balance: Option<LndAmount>,
}

#[derive(Debug, Deserialize)]
struct LndBalanceResponse {
    total_balance: Option<String>,
    #[allow(dead_code)]
    confirmed_balance: Option<String>,
}

#[derive(Debug, Deserialize)]
struct LndAmount {
    sat: Option<String>,
}

impl RpcHandler {
    pub(super) async fn handle_lnd_getinfo(&self) -> Result<serde_json::Value> {
        let macaroon_path =
            "/var/lib/archipelago/lnd/data/chain/bitcoin/mainnet/admin.macaroon";

        let macaroon_bytes = tokio::fs::read(macaroon_path)
            .await
            .context("Failed to read LND admin macaroon — is LND installed?")?;
        let macaroon_hex = hex::encode(&macaroon_bytes);

        let client = reqwest::Client::builder()
            .timeout(std::time::Duration::from_secs(10))
            .danger_accept_invalid_certs(true)
            .build()
            .context("Failed to create HTTP client")?;

        let get_info: LndGetInfoResponse = client
            .get("https://127.0.0.1:8080/v1/getinfo")
            .header("Grpc-Metadata-macaroon", &macaroon_hex)
            .send()
            .await
            .context("LND REST connection failed")?
            .json()
            .await
            .context("Failed to parse LND getinfo response")?;

        let channel_balance: LndChannelBalanceResponse = match client
            .get("https://127.0.0.1:8080/v1/balance/channels")
            .header("Grpc-Metadata-macaroon", &macaroon_hex)
            .send()
            .await
        {
            Ok(resp) => resp.json().await.unwrap_or(LndChannelBalanceResponse {
                local_balance: None,
                pending_open_local_balance: None,
            }),
            Err(_) => LndChannelBalanceResponse {
                local_balance: None,
                pending_open_local_balance: None,
            },
        };

        let wallet_balance: LndBalanceResponse = match client
            .get("https://127.0.0.1:8080/v1/balance/blockchain")
            .header("Grpc-Metadata-macaroon", &macaroon_hex)
            .send()
            .await
        {
            Ok(resp) => resp.json().await.unwrap_or(LndBalanceResponse {
                total_balance: None,
                confirmed_balance: None,
            }),
            Err(_) => LndBalanceResponse {
                total_balance: None,
                confirmed_balance: None,
            },
        };

        let info = LndInfo {
            alias: get_info.alias.unwrap_or_default(),
            num_active_channels: get_info.num_active_channels.unwrap_or(0),
            num_peers: get_info.num_peers.unwrap_or(0),
            synced_to_chain: get_info.synced_to_chain.unwrap_or(false),
            block_height: get_info.block_height.unwrap_or(0),
            balance_sats: wallet_balance
                .total_balance
                .and_then(|s| s.parse().ok())
                .unwrap_or(0),
            channel_balance_sats: channel_balance
                .local_balance
                .and_then(|a| a.sat.and_then(|s| s.parse().ok()))
                .unwrap_or(0),
            pending_open_balance: channel_balance
                .pending_open_local_balance
                .and_then(|a| a.sat.and_then(|s| s.parse().ok()))
                .unwrap_or(0),
        };

        Ok(serde_json::to_value(info)?)
    }
}
