//! BIP70 Payment Protocol P2P Message Handlers
//!
//! Handles incoming BIP70 messages from the P2P network.
//! Uses unified PaymentProcessor for transport-agnostic payment processing.

use crate::network::protocol::{
    GetPaymentRequestMessage, PaymentACKMessage, PaymentMessage, PaymentRequestMessage,
};
use crate::payment::processor::PaymentProcessor;
use anyhow::Result;
use blvm_protocol::payment::Bip70Error;
use hex;
use std::sync::Arc;

/// Handle GetPaymentRequest message
///
/// Merchant node responds with PaymentRequest signed with their Bitcoin key.
/// Uses unified PaymentProcessor for transport-agnostic processing.
pub async fn handle_get_payment_request(
    request: &GetPaymentRequestMessage,
    processor: Option<Arc<PaymentProcessor>>,
) -> Result<PaymentRequestMessage> {
    let processor = processor.ok_or_else(|| anyhow::anyhow!("Payment processor not available"))?;

    // Convert payment_id from bytes to string
    let payment_id = hex::encode(&request.payment_id);

    // Get payment request using unified processor
    let payment_request = processor
        .get_payment_request(&payment_id)
        .await
        .map_err(|e| anyhow::anyhow!("Failed to get payment request: {}", e))?;

    // Extract signature from embedded PaymentRequest signature field.
    // The PaymentRequest is already signed when created via PaymentProcessor.
    // If unsigned (None), reject rather than forwarding an unsigned payload over P2P.
    let merchant_signature = match payment_request.signature.clone() {
        Some(sig) if !sig.is_empty() => sig,
        _ => {
            return Err(anyhow::anyhow!(
                "PaymentRequest for {} is unsigned; refusing to forward unsigned BIP70 payload over P2P",
                payment_id
            ));
        }
    };

    // Extract merchant pubkey from PaymentRequest if available, otherwise use from request
    let merchant_pubkey = payment_request
        .merchant_pubkey
        .clone()
        .unwrap_or_else(|| request.merchant_pubkey.clone());

    // Convert to P2P message format
    Ok(PaymentRequestMessage {
        payment_request,
        payment_id: request.payment_id.clone(),
        merchant_pubkey,
        merchant_signature,
        #[cfg(feature = "ctv")]
        covenant_proof: None, // Can be set if CTV proof is created
    })
}

/// Handle Payment message
///
/// Merchant node processes payment and responds with PaymentACK.
/// Uses unified PaymentProcessor for transport-agnostic processing.
pub async fn handle_payment(
    payment_msg: &PaymentMessage,
    processor: Option<Arc<PaymentProcessor>>,
    merchant_private_key: Option<&[u8; 32]>,
) -> Result<PaymentACKMessage> {
    let processor = processor.ok_or_else(|| anyhow::anyhow!("Payment processor not available"))?;

    // Convert payment_id from bytes to string
    let payment_id = hex::encode(&payment_msg.payment_id);

    // Process payment using unified processor
    // PaymentProtocolServer::process_payment() signs the PaymentACK if merchant_key is provided
    let payment_ack = processor
        .process_payment(
            payment_msg.payment.clone(),
            payment_id,
            merchant_private_key,
        )
        .await
        .map_err(|e| anyhow::anyhow!("Payment processing failed: {}", e))?;

    // Extract signature from embedded PaymentACK signature field.
    // The PaymentACK is signed by PaymentProtocolServer::process_payment() when a merchant key is
    // provided. Reject unsigned ACKs to prevent forwarding unsigned P2P payloads.
    let merchant_signature = match payment_ack.signature.clone() {
        Some(sig) if !sig.is_empty() => sig,
        _ => {
            return Err(anyhow::anyhow!(
                "PaymentACK is unsigned (no merchant_key provided?); refusing to forward unsigned BIP70 payload over P2P"
            ));
        }
    };

    // Convert to P2P message format
    Ok(PaymentACKMessage {
        payment_ack,
        payment_id: payment_msg.payment_id.clone(),
        merchant_signature,
    })
}

/// Validate PaymentRequest message from P2P network
pub fn validate_payment_request_message(msg: &PaymentRequestMessage) -> Result<(), Bip70Error> {
    use blvm_protocol::payment::PaymentProtocolClient;
    PaymentProtocolClient::validate_payment_request(
        &msg.payment_request,
        Some(&msg.merchant_pubkey),
    )
}

/// Validate PaymentACK message from merchant
pub fn validate_payment_ack_message(
    ack: &PaymentACKMessage,
    merchant_pubkey: &[u8],
) -> Result<(), Bip70Error> {
    use blvm_protocol::payment::PaymentProtocolClient;
    PaymentProtocolClient::validate_payment_ack(
        &ack.payment_ack,
        &ack.merchant_signature,
        merchant_pubkey,
    )
}

#[cfg(test)]
mod tests {
    use super::*;

    #[tokio::test]
    async fn get_payment_request_requires_processor() {
        let request = GetPaymentRequestMessage {
            merchant_pubkey: vec![0x02; 33],
            payment_id: vec![0xab; 32],
            network: "regtest".into(),
        };
        assert!(handle_get_payment_request(&request, None).await.is_err());
    }

    #[tokio::test]
    async fn handle_payment_requires_processor() {
        let payment = PaymentMessage {
            payment_id: vec![0xcd; 32],
            payment: blvm_protocol::payment::Payment {
                merchant_data: None,
                transactions: vec![],
                refund_to: None,
                memo: None,
            },
            customer_signature: None,
        };
        assert!(handle_payment(&payment, None, None).await.is_err());
    }
}
