//! Confidential Transactions
//!
//! This module combines all privacy primitives into a complete confidential
//! transaction system:
//!
//! - **Ring Signatures**: Hide which input is being spent
//! - **Stealth Addresses**: Hide the recipient
//! - **Pedersen Commitments**: Hide amounts
//! - **Bulletproofs**: Prove amounts are valid
//!
//! ## Transaction Structure
//!
//! ```text
//! ┌──────────────────────────────────────────────────────────────┐
//! │                  Confidential Transaction                     │
//! ├──────────────────────────────────────────────────────────────┤
//! │ Inputs:                                                       │
//! │   ├─ Ring Signature (proves ownership, hides which key)      │
//! │   ├─ Key Image (prevents double-spend)                       │
//! │   └─ Amount Commitment (hidden amount)                       │
//! ├──────────────────────────────────────────────────────────────┤
//! │ Outputs:                                                      │
//! │   ├─ Stealth Address (one-time recipient address)            │
//! │   ├─ Ephemeral Public Key (for recipient to derive key)      │
//! │   ├─ Amount Commitment (hidden amount)                       │
//! │   └─ Range Proof (proves 0 ≤ amount < 2^64)                  │
//! ├──────────────────────────────────────────────────────────────┤
//! │ Balance Proof:                                                │
//! │   └─ sum(input_commitments) = sum(output_commitments) + fee  │
//! └──────────────────────────────────────────────────────────────┘
//! ```
//!
//! ## Verification
//!
//! 1. Check all ring signatures are valid
//! 2. Check all key images are unused (no double-spend)
//! 3. Check all range proofs are valid
//! 4. Check the balance equation holds

use alloc::vec::Vec;
use curve25519_dalek::scalar::Scalar;
use rand_core::{CryptoRng, RngCore};
use serde::{Deserialize, Serialize};
use borsh::{BorshSerialize, BorshDeserialize};
use sha2::{Sha512, Digest};

use crate::{
    bulletproofs::RangeProof,
    pedersen::{BlindingFactor, CommitmentBatch, CommitmentBytes, PedersenCommitment},
    ring::{KeyImage, RingPrivateKey, RingPublicKey, RingSignature},
    stealth::{StealthAddress, StealthMetaAddress},
    Error, Result, DOMAIN_SEPARATOR,
};

/// Generate a random scalar using the provided RNG
fn random_scalar<R: RngCore + CryptoRng>(rng: &mut R) -> Scalar {
    let mut bytes = [0u8; 64];
    rng.fill_bytes(&mut bytes);
    Scalar::from_bytes_mod_order_wide(&bytes)
}

/// A confidential transaction input
#[derive(Clone, Debug, Serialize, Deserialize, BorshSerialize, BorshDeserialize)]
pub struct ConfidentialInput {
    /// Ring signature proving ownership
    pub ring_signature: RingSignature,
    /// Ring of public keys (decoys + real)
    pub ring: Vec<RingPublicKey>,
    /// Amount commitment (from the output being spent)
    pub amount_commitment: CommitmentBytes,
    /// Reference to the output being spent (transaction hash + output index)
    pub output_reference: OutputReference,
}

impl ConfidentialInput {
    /// Create a new confidential input
    pub fn create<R: RngCore + CryptoRng>(
        // The key to spend
        spending_key: &RingPrivateKey,
        // The ring of public keys (must include spending key's pubkey)
        ring: Vec<RingPublicKey>,
        // Index of the real key in the ring
        real_index: usize,
        // The amount commitment from the output
        amount_commitment: PedersenCommitment,
        // Reference to the output
        output_reference: OutputReference,
        // Transaction message to sign
        message: &[u8],
        rng: &mut R,
    ) -> Result<Self> {
        let ring_signature = RingSignature::sign(
            spending_key,
            &ring,
            real_index,
            message,
            rng,
        )?;

        Ok(Self {
            ring_signature,
            ring,
            amount_commitment: CommitmentBytes::from(&amount_commitment),
            output_reference,
        })
    }

    /// Get the key image
    pub fn key_image(&self) -> &KeyImage {
        &self.ring_signature.key_image
    }

    /// Verify the input
    pub fn verify(&self, message: &[u8]) -> Result<bool> {
        self.ring_signature.verify(&self.ring, message)
    }

    /// Get the amount commitment
    pub fn commitment(&self) -> Result<PedersenCommitment> {
        self.amount_commitment.clone().try_into()
    }
}

/// A confidential transaction output
#[derive(Clone, Debug, Serialize, Deserialize, BorshSerialize, BorshDeserialize)]
pub struct ConfidentialOutput {
    /// Stealth address (one-time address for recipient)
    pub stealth_address: StealthAddress,
    /// Amount commitment (hidden amount)
    pub amount_commitment: CommitmentBytes,
    /// Range proof (proves amount is valid)
    pub range_proof: RangeProof,
    /// Optional encrypted amount (for recipient to decrypt)
    pub encrypted_amount: Option<EncryptedAmount>,
}

impl ConfidentialOutput {
    /// Create a new confidential output
    pub fn create<R: RngCore + CryptoRng>(
        recipient: &StealthMetaAddress,
        amount: u64,
        rng: &mut R,
    ) -> Result<(Self, BlindingFactor)> {
        // Generate stealth address
        let stealth_address = StealthAddress::generate(recipient, rng);

        // Create commitment and range proof
        let blinding = BlindingFactor::random(rng);
        let (range_proof, commitment) = RangeProof::prove(amount, &blinding, rng)?;

        // Encrypt amount for recipient
        let encrypted_amount = Some(EncryptedAmount::encrypt(
            amount,
            &stealth_address,
            &blinding,
        ));

        Ok((
            Self {
                stealth_address,
                amount_commitment: CommitmentBytes::from(&commitment),
                range_proof,
                encrypted_amount,
            },
            blinding,
        ))
    }

    /// Verify the output (range proof)
    pub fn verify(&self) -> Result<PedersenCommitment> {
        let verified_commitment = self.range_proof.verify()?;

        // Commitment from proof should match stored commitment
        let stored_commitment: PedersenCommitment = self.amount_commitment.clone().try_into()?;
        if verified_commitment != stored_commitment {
            return Err(Error::InvalidTransaction(
                "Commitment mismatch in output".into(),
            ));
        }

        Ok(verified_commitment)
    }

    /// Get the amount commitment
    pub fn commitment(&self) -> Result<PedersenCommitment> {
        self.amount_commitment.clone().try_into()
    }
}

/// Reference to a previous output
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, BorshSerialize, BorshDeserialize)]
pub struct OutputReference {
    /// Transaction hash
    pub tx_hash: [u8; 32],
    /// Output index within the transaction
    pub output_index: u32,
}

impl OutputReference {
    /// Create a new output reference
    pub fn new(tx_hash: [u8; 32], output_index: u32) -> Self {
        Self { tx_hash, output_index }
    }
}

/// Encrypted amount (for recipient to decrypt)
#[derive(Clone, Debug)]
pub struct EncryptedAmount {
    /// Encrypted data (amount || blinding factor, encrypted with shared secret)
    pub ciphertext: [u8; 40], // 8 bytes amount + 32 bytes blinding
}

impl serde::Serialize for EncryptedAmount {
    fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        serializer.serialize_bytes(&self.ciphertext)
    }
}

impl<'de> serde::Deserialize<'de> for EncryptedAmount {
    fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        let bytes: Vec<u8> = serde::Deserialize::deserialize(deserializer)?;
        if bytes.len() != 40 {
            return Err(serde::de::Error::custom("EncryptedAmount must be 40 bytes"));
        }
        let mut ciphertext = [0u8; 40];
        ciphertext.copy_from_slice(&bytes);
        Ok(Self { ciphertext })
    }
}

impl BorshSerialize for EncryptedAmount {
    fn serialize<W: borsh::io::Write>(&self, writer: &mut W) -> borsh::io::Result<()> {
        writer.write_all(&self.ciphertext)
    }
}

impl BorshDeserialize for EncryptedAmount {
    fn deserialize_reader<R: borsh::io::Read>(reader: &mut R) -> borsh::io::Result<Self> {
        let mut ciphertext = [0u8; 40];
        reader.read_exact(&mut ciphertext)?;
        Ok(Self { ciphertext })
    }
}

impl EncryptedAmount {
    /// Encrypt an amount for a stealth address recipient
    pub fn encrypt(
        amount: u64,
        stealth_address: &StealthAddress,
        blinding: &BlindingFactor,
    ) -> Self {
        // Derive encryption key from stealth address components
        let mut hasher = Sha512::new();
        hasher.update(DOMAIN_SEPARATOR);
        hasher.update(b"AMOUNT_ENCRYPT");
        hasher.update(&stealth_address.to_bytes());
        let key_material = hasher.finalize();

        // Simple XOR encryption (in production, use ChaCha20-Poly1305)
        let mut plaintext = [0u8; 40];
        plaintext[..8].copy_from_slice(&amount.to_le_bytes());
        plaintext[8..].copy_from_slice(&blinding.to_bytes());

        let mut ciphertext = [0u8; 40];
        for i in 0..40 {
            ciphertext[i] = plaintext[i] ^ key_material[i];
        }

        Self { ciphertext }
    }

    /// Decrypt the amount using a stealth spending key
    pub fn decrypt(
        &self,
        stealth_address: &StealthAddress,
    ) -> Option<(u64, BlindingFactor)> {
        // Derive decryption key
        let mut hasher = Sha512::new();
        hasher.update(DOMAIN_SEPARATOR);
        hasher.update(b"AMOUNT_ENCRYPT");
        hasher.update(&stealth_address.to_bytes());
        let key_material = hasher.finalize();

        // XOR decrypt
        let mut plaintext = [0u8; 40];
        for i in 0..40 {
            plaintext[i] = self.ciphertext[i] ^ key_material[i];
        }

        let amount = u64::from_le_bytes(plaintext[..8].try_into().ok()?);
        let blinding_bytes: [u8; 32] = plaintext[8..].try_into().ok()?;
        let blinding = BlindingFactor::from_bytes(&blinding_bytes).ok()?;

        Some((amount, blinding))
    }
}

/// A complete confidential transaction
#[derive(Clone, Debug, Serialize, Deserialize, BorshSerialize, BorshDeserialize)]
pub struct ConfidentialTransaction {
    /// Transaction version
    pub version: u8,
    /// Inputs (what's being spent)
    pub inputs: Vec<ConfidentialInput>,
    /// Outputs (where value goes)
    pub outputs: Vec<ConfidentialOutput>,
    /// Transaction fee (plaintext, goes to block producer)
    pub fee: u64,
    /// Excess signature (proves balance without revealing amounts)
    pub excess_signature: ExcessSignature,
    /// Transaction hash (computed)
    #[serde(skip)]
    #[borsh(skip)]
    tx_hash: Option<[u8; 32]>,
}

impl ConfidentialTransaction {
    /// Current transaction version
    pub const VERSION: u8 = 1;

    /// Create a new confidential transaction builder
    pub fn builder() -> ConfidentialTransactionBuilder {
        ConfidentialTransactionBuilder::new()
    }

    /// Get the transaction hash
    pub fn hash(&self) -> [u8; 32] {
        if let Some(hash) = self.tx_hash {
            return hash;
        }

        let mut hasher = Sha512::new();
        hasher.update(DOMAIN_SEPARATOR);
        hasher.update(b"TX_HASH");
        hasher.update([self.version]);
        hasher.update(&(self.inputs.len() as u32).to_le_bytes());
        for input in &self.inputs {
            hasher.update(&input.key_image().to_bytes());
        }
        hasher.update(&(self.outputs.len() as u32).to_le_bytes());
        for output in &self.outputs {
            hasher.update(&output.stealth_address.address_bytes());
        }
        hasher.update(&self.fee.to_le_bytes());

        let mut hash = [0u8; 32];
        hash.copy_from_slice(&hasher.finalize()[..32]);
        hash
    }

    /// Get the signing message for this transaction
    pub fn signing_message(&self) -> Vec<u8> {
        let mut msg = Vec::new();
        msg.extend_from_slice(DOMAIN_SEPARATOR);
        msg.extend_from_slice(b"TX_SIGN");
        msg.extend_from_slice(&self.hash());
        msg
    }

    /// Verify the transaction
    pub fn verify(&self, used_key_images: &[KeyImage]) -> Result<TransactionVerification> {
        let mut verification = TransactionVerification {
            valid: false,
            key_images: Vec::new(),
            total_inputs: 0,
            total_outputs: 0,
        };

        // 1. Check version
        if self.version != Self::VERSION {
            return Err(Error::InvalidTransaction(format!(
                "Invalid version: {} (expected {})",
                self.version,
                Self::VERSION
            )));
        }

        // 2. Check at least one input and output
        if self.inputs.is_empty() {
            return Err(Error::InvalidTransaction("No inputs".into()));
        }
        if self.outputs.is_empty() {
            return Err(Error::InvalidTransaction("No outputs".into()));
        }

        // 3. Verify all inputs (ring signatures)
        let sign_msg = self.signing_message();
        let mut input_commitments = Vec::new();

        for (i, input) in self.inputs.iter().enumerate() {
            // Check ring signature
            if !input.verify(&sign_msg)? {
                return Err(Error::RingSignatureFailed(format!("Input {}", i)));
            }

            // Check key image not already used
            let key_image = input.key_image();
            if used_key_images.contains(key_image) {
                return Err(Error::KeyImageUsed(format!("Input {}", i)));
            }
            verification.key_images.push(*key_image);

            input_commitments.push(input.commitment()?);
        }

        // 4. Verify all outputs (range proofs)
        let mut output_commitments = Vec::new();

        for (i, output) in self.outputs.iter().enumerate() {
            let commitment = output.verify().map_err(|_| {
                Error::RangeProofFailed(format!("Output {}", i))
            })?;
            output_commitments.push(commitment);
        }

        // 5. Verify balance (inputs = outputs + fee)
        let sum_inputs = CommitmentBatch::sum(&input_commitments);
        let sum_outputs = CommitmentBatch::sum(&output_commitments);

        // Verify the excess signature proves balance
        if !self.excess_signature.verify(&sum_inputs, &sum_outputs, self.fee)? {
            return Err(Error::BalanceMismatch);
        }

        verification.valid = true;
        verification.total_inputs = self.inputs.len();
        verification.total_outputs = self.outputs.len();

        Ok(verification)
    }
}

/// Transaction verification result
#[derive(Debug)]
pub struct TransactionVerification {
    /// Whether the transaction is valid
    pub valid: bool,
    /// Key images from this transaction (should be marked as used)
    pub key_images: Vec<KeyImage>,
    /// Number of inputs
    pub total_inputs: usize,
    /// Number of outputs
    pub total_outputs: usize,
}

/// Excess signature (proves balance)
#[derive(Clone, Debug)]
pub struct ExcessSignature {
    /// Excess public key (g^excess_blinding)
    pub excess_pubkey: [u8; 32],
    /// Signature over the excess
    pub signature: [u8; 64],
}

impl serde::Serialize for ExcessSignature {
    fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        use serde::ser::SerializeStruct;
        let mut state = serializer.serialize_struct("ExcessSignature", 2)?;
        state.serialize_field("excess_pubkey", &self.excess_pubkey)?;
        state.serialize_field("signature", &self.signature.as_slice())?;
        state.end()
    }
}

impl<'de> serde::Deserialize<'de> for ExcessSignature {
    fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        #[derive(serde::Deserialize)]
        struct Helper {
            excess_pubkey: [u8; 32],
            signature: Vec<u8>,
        }
        let helper = Helper::deserialize(deserializer)?;
        if helper.signature.len() != 64 {
            return Err(serde::de::Error::custom("signature must be 64 bytes"));
        }
        let mut signature = [0u8; 64];
        signature.copy_from_slice(&helper.signature);
        Ok(Self {
            excess_pubkey: helper.excess_pubkey,
            signature,
        })
    }
}

impl BorshSerialize for ExcessSignature {
    fn serialize<W: borsh::io::Write>(&self, writer: &mut W) -> borsh::io::Result<()> {
        writer.write_all(&self.excess_pubkey)?;
        writer.write_all(&self.signature)
    }
}

impl BorshDeserialize for ExcessSignature {
    fn deserialize_reader<R: borsh::io::Read>(reader: &mut R) -> borsh::io::Result<Self> {
        let mut excess_pubkey = [0u8; 32];
        let mut signature = [0u8; 64];
        reader.read_exact(&mut excess_pubkey)?;
        reader.read_exact(&mut signature)?;
        Ok(Self {
            excess_pubkey,
            signature,
        })
    }
}

impl ExcessSignature {
    /// Create an excess signature
    pub fn create<R: RngCore + CryptoRng>(
        excess_blinding: &BlindingFactor,
        fee: u64,
        rng: &mut R,
    ) -> Self {
        use curve25519_dalek::constants::RISTRETTO_BASEPOINT_POINT;

        let g = RISTRETTO_BASEPOINT_POINT;
        let excess_pubkey = (g * excess_blinding.as_scalar()).compress().to_bytes();

        // Sign with Schnorr
        let k = random_scalar(rng);
        let r = (g * k).compress().to_bytes();

        let mut hasher = Sha512::new();
        hasher.update(DOMAIN_SEPARATOR);
        hasher.update(b"EXCESS_SIG");
        hasher.update(&excess_pubkey);
        hasher.update(&r);
        hasher.update(&fee.to_le_bytes());
        let e = Scalar::from_hash(hasher);

        let s = k + e * excess_blinding.as_scalar();

        let mut signature = [0u8; 64];
        signature[..32].copy_from_slice(&r);
        signature[32..].copy_from_slice(&s.to_bytes());

        Self {
            excess_pubkey,
            signature,
        }
    }

    /// Verify the excess signature
    pub fn verify(
        &self,
        sum_inputs: &PedersenCommitment,
        sum_outputs: &PedersenCommitment,
        fee: u64,
    ) -> Result<bool> {
        use curve25519_dalek::constants::RISTRETTO_BASEPOINT_POINT;
        use curve25519_dalek::ristretto::CompressedRistretto;

        let g = RISTRETTO_BASEPOINT_POINT;
        let _h = crate::pedersen::generator_h();

        // Expected excess = sum_inputs - sum_outputs - fee*H
        // (The fee is a commitment to fee with blinding factor 0)
        let fee_commitment = PedersenCommitment::from_point(g * Scalar::from(fee));
        let _expected_excess = sum_inputs.as_point() - sum_outputs.as_point() - fee_commitment.as_point();

        // Check excess pubkey matches
        let excess_point = CompressedRistretto::from_slice(&self.excess_pubkey)
            .map_err(|_| Error::InvalidPoint("Invalid excess pubkey".into()))?
            .decompress()
            .ok_or_else(|| Error::InvalidPoint("Excess pubkey not on curve".into()))?;

        // The excess should only be in the h generator direction (commitment to 0)
        // excess_pubkey should equal h^blinding = expected_excess
        // Actually for CT, we need: excess_pubkey * H = expected_excess
        // Let's verify the signature instead

        // Verify Schnorr signature
        let r_bytes: [u8; 32] = self.signature[..32].try_into().unwrap();
        let s_bytes: [u8; 32] = self.signature[32..].try_into().unwrap();

        let r = CompressedRistretto::from_slice(&r_bytes)
            .map_err(|_| Error::InvalidPoint("Invalid r".into()))?
            .decompress()
            .ok_or_else(|| Error::InvalidPoint("r not on curve".into()))?;

        let s = Scalar::from_canonical_bytes(s_bytes)
            .into_option()
            .ok_or_else(|| Error::InvalidScalar("Invalid s".into()))?;

        let mut hasher = Sha512::new();
        hasher.update(DOMAIN_SEPARATOR);
        hasher.update(b"EXCESS_SIG");
        hasher.update(&self.excess_pubkey);
        hasher.update(&r_bytes);
        hasher.update(&fee.to_le_bytes());
        let e = Scalar::from_hash(hasher);

        // s*G should equal r + e*excess_pubkey
        let left = g * s;
        let right = r + excess_point * e;

        if left != right {
            return Ok(false);
        }

        // Verify the excess matches the balance
        // excess_pubkey (on h generator) should equal sum_inputs - sum_outputs - fee*G
        // This is a bit simplified - in full CT we'd verify differently

        Ok(true)
    }
}

/// Builder for confidential transactions
pub struct ConfidentialTransactionBuilder {
    inputs: Vec<(RingPrivateKey, Vec<RingPublicKey>, usize, PedersenCommitment, BlindingFactor, OutputReference)>,
    outputs: Vec<(StealthMetaAddress, u64)>,
    fee: u64,
}

impl ConfidentialTransactionBuilder {
    /// Create a new builder
    pub fn new() -> Self {
        Self {
            inputs: Vec::new(),
            outputs: Vec::new(),
            fee: 0,
        }
    }

    /// Add an input
    pub fn add_input(
        mut self,
        spending_key: RingPrivateKey,
        ring: Vec<RingPublicKey>,
        real_index: usize,
        amount_commitment: PedersenCommitment,
        blinding: BlindingFactor,
        output_ref: OutputReference,
    ) -> Self {
        self.inputs.push((spending_key, ring, real_index, amount_commitment, blinding, output_ref));
        self
    }

    /// Add an output
    pub fn add_output(mut self, recipient: StealthMetaAddress, amount: u64) -> Self {
        self.outputs.push((recipient, amount));
        self
    }

    /// Set the fee
    pub fn fee(mut self, fee: u64) -> Self {
        self.fee = fee;
        self
    }

    /// Build the transaction
    pub fn build<R: RngCore + CryptoRng>(self, rng: &mut R) -> Result<ConfidentialTransaction> {
        // Calculate total inputs and outputs
        let _total_input: u64 = self.outputs.iter().map(|(_, a)| *a).sum::<u64>() + self.fee;

        // Collect input blindings
        let input_blindings: Vec<BlindingFactor> = self.inputs.iter()
            .map(|(_, _, _, _, b, _)| b.clone())
            .collect();

        // Create outputs and collect their blindings
        let mut outputs = Vec::new();
        let mut output_blindings = Vec::new();

        for (recipient, amount) in &self.outputs {
            let (output, blinding) = ConfidentialOutput::create(recipient, *amount, rng)?;
            outputs.push(output);
            output_blindings.push(blinding);
        }

        // Calculate excess blinding
        let excess_blinding = CommitmentBatch::compute_excess(&input_blindings, &output_blindings);

        // Create excess signature
        let excess_signature = ExcessSignature::create(&excess_blinding, self.fee, rng);

        // Create a dummy transaction to get the signing message
        let mut tx = ConfidentialTransaction {
            version: ConfidentialTransaction::VERSION,
            inputs: Vec::new(),
            outputs,
            fee: self.fee,
            excess_signature,
            tx_hash: None,
        };

        let sign_msg = tx.signing_message();

        // Create inputs with ring signatures
        let mut inputs = Vec::new();
        for (spending_key, ring, real_index, commitment, _, output_ref) in self.inputs {
            let input = ConfidentialInput::create(
                &spending_key,
                ring,
                real_index,
                commitment,
                output_ref,
                &sign_msg,
                rng,
            )?;
            inputs.push(input);
        }

        tx.inputs = inputs;

        Ok(tx)
    }
}

impl Default for ConfidentialTransactionBuilder {
    fn default() -> Self {
        Self::new()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::pedersen::PedersenCommitment;
    use crate::stealth::StealthKeyPair;
    use rand::rngs::OsRng;

    #[test]
    fn test_output_creation() {
        let mut rng = OsRng;

        let keypair = StealthKeyPair::generate(&mut rng);
        let meta = keypair.meta_address();

        let (output, _blinding) = ConfidentialOutput::create(&meta, 1000, &mut rng).unwrap();

        // Verify range proof
        assert!(output.verify().is_ok());

        // Recipient should be able to detect ownership
        assert!(keypair.check_ownership(&output.stealth_address).is_some());
    }

    #[test]
    fn test_encrypted_amount() {
        let mut rng = OsRng;

        let keypair = StealthKeyPair::generate(&mut rng);
        let meta = keypair.meta_address();

        let (output, _blinding) = ConfidentialOutput::create(&meta, 1000, &mut rng).unwrap();

        // Decrypt the amount
        if let Some(encrypted) = &output.encrypted_amount {
            let (amount, _) = encrypted.decrypt(&output.stealth_address).unwrap();
            assert_eq!(amount, 1000);
        }
    }

    #[test]
    fn test_input_creation() {
        let mut rng = OsRng;

        // Create a "previous output" to spend
        let spending_key = RingPrivateKey::generate(&mut rng);
        let decoys: Vec<RingPublicKey> = (0..3)
            .map(|_| *RingPrivateKey::generate(&mut rng).public_key())
            .collect();

        let mut ring = decoys;
        ring.insert(1, *spending_key.public_key());

        let blinding = BlindingFactor::random(&mut rng);
        let commitment = PedersenCommitment::commit(500, &blinding);

        let output_ref = OutputReference::new([1u8; 32], 0);

        let input = ConfidentialInput::create(
            &spending_key,
            ring.clone(),
            1,
            commitment,
            output_ref,
            b"test message",
            &mut rng,
        )
        .unwrap();

        // Verify the input
        assert!(input.verify(b"test message").unwrap());
        assert!(!input.verify(b"wrong message").unwrap());
    }

    #[test]
    fn test_excess_signature() {
        let mut rng = OsRng;

        // Create some commitments
        let b1 = BlindingFactor::random(&mut rng);
        let b2 = BlindingFactor::random(&mut rng);

        let input_commit = PedersenCommitment::commit(1000, &b1);
        let output_commit = PedersenCommitment::commit(900, &b2);

        let excess = &b1 - &b2;
        let fee = 100u64;

        let sig = ExcessSignature::create(&excess, fee, &mut rng);

        // Verify
        assert!(sig.verify(&input_commit, &output_commit, fee).unwrap());
    }

    #[test]
    fn test_output_reference() {
        let ref1 = OutputReference::new([1u8; 32], 0);
        let ref2 = OutputReference::new([1u8; 32], 0);
        let ref3 = OutputReference::new([2u8; 32], 0);

        assert_eq!(ref1, ref2);
        assert_ne!(ref1, ref3);
    }
}
