//! Tests that verify compatibility with TypeScript and Go SDKs.
//!
//! These tests use test vectors generated by the TypeScript and Go SDKs
//! to ensure the Rust implementation produces identical results.

use bsv_rs::primitives::ec::{PrivateKey, PublicKey};
use bsv_rs::primitives::symmetric::SymmetricKey;
use bsv_rs::primitives::{from_base64, from_hex};
use serde::Deserialize;
use std::fs;

// ============================================================================
// Test Vector Structures
// ============================================================================

/// Test vector for BRC-42 private key derivation.
#[derive(Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
struct Brc42PrivateVector {
    sender_public_key: String,
    recipient_private_key: String,
    invoice_number: String,
    private_key: String,
}

/// Test vector for BRC-42 public key derivation.
#[derive(Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
struct Brc42PublicVector {
    sender_private_key: String,
    recipient_public_key: String,
    invoice_number: String,
    public_key: String,
}

/// Test vector for symmetric key encryption.
#[derive(Deserialize, Debug)]
struct SymmetricKeyVector {
    ciphertext: String,
    key: String,
    plaintext: String,
}

/// Test vector for DRBG.
#[derive(Deserialize, Debug)]
#[allow(dead_code)]
struct DrbgVector {
    name: String,
    entropy: String,
    nonce: String,
    pers: Option<String>,
    add: Vec<Option<String>>,
    expected: String,
}

// ============================================================================
// Vector Loading Functions
// ============================================================================

fn load_brc42_private_vectors() -> Vec<Brc42PrivateVector> {
    let data = fs::read_to_string("tests/vectors/brc42_private.json")
        .expect("Failed to read brc42_private.json");
    serde_json::from_str(&data).expect("Failed to parse brc42_private.json")
}

fn load_brc42_public_vectors() -> Vec<Brc42PublicVector> {
    let data = fs::read_to_string("tests/vectors/brc42_public.json")
        .expect("Failed to read brc42_public.json");
    serde_json::from_str(&data).expect("Failed to parse brc42_public.json")
}

fn load_symmetric_key_vectors() -> Vec<SymmetricKeyVector> {
    let data = fs::read_to_string("tests/vectors/symmetric_key.json")
        .expect("Failed to read symmetric_key.json");
    serde_json::from_str(&data).expect("Failed to parse symmetric_key.json")
}

fn load_drbg_vectors() -> Vec<DrbgVector> {
    let data = fs::read_to_string("tests/vectors/drbg.json").expect("Failed to read drbg.json");
    serde_json::from_str(&data).expect("Failed to parse drbg.json")
}

// ============================================================================
// BRC-42 Key Derivation Tests
// ============================================================================

#[test]
fn test_brc42_private_derivation_vectors() {
    let vectors = load_brc42_private_vectors();

    for (i, v) in vectors.iter().enumerate() {
        let sender_pub = PublicKey::from_hex(&v.sender_public_key)
            .unwrap_or_else(|e| panic!("Vector {}: Failed to parse sender public key: {}", i, e));

        let recipient_priv = PrivateKey::from_hex(&v.recipient_private_key).unwrap_or_else(|e| {
            panic!("Vector {}: Failed to parse recipient private key: {}", i, e)
        });

        let derived = recipient_priv
            .derive_child(&sender_pub, &v.invoice_number)
            .unwrap_or_else(|e| panic!("Vector {}: Failed to derive child key: {}", i, e));

        assert_eq!(
            derived.to_hex(),
            v.private_key,
            "BRC-42 private derivation failed for vector {} (invoice: {})",
            i,
            v.invoice_number
        );
    }
}

#[test]
fn test_brc42_public_derivation_vectors() {
    let vectors = load_brc42_public_vectors();

    for (i, v) in vectors.iter().enumerate() {
        let sender_priv = PrivateKey::from_hex(&v.sender_private_key)
            .unwrap_or_else(|e| panic!("Vector {}: Failed to parse sender private key: {}", i, e));

        let recipient_pub = PublicKey::from_hex(&v.recipient_public_key).unwrap_or_else(|e| {
            panic!("Vector {}: Failed to parse recipient public key: {}", i, e)
        });

        let derived = recipient_pub
            .derive_child(&sender_priv, &v.invoice_number)
            .unwrap_or_else(|e| panic!("Vector {}: Failed to derive child key: {}", i, e));

        assert_eq!(
            derived.to_hex(),
            v.public_key,
            "BRC-42 public derivation failed for vector {} (invoice: {})",
            i,
            v.invoice_number
        );
    }
}

// ============================================================================
// Symmetric Key Cross-SDK Compatibility Tests
// ============================================================================

#[test]
fn test_symmetric_key_cross_sdk_vectors() {
    let vectors = load_symmetric_key_vectors();

    for (i, v) in vectors.iter().enumerate() {
        // Key is Base64 encoded
        let key_bytes = from_base64(&v.key)
            .unwrap_or_else(|e| panic!("Vector {}: Failed to decode key: {}", i, e));

        let key = SymmetricKey::from_bytes(&key_bytes)
            .unwrap_or_else(|e| panic!("Vector {}: Failed to create symmetric key: {}", i, e));

        // Ciphertext is Base64 encoded
        let ciphertext = from_base64(&v.ciphertext)
            .unwrap_or_else(|e| panic!("Vector {}: Failed to decode ciphertext: {}", i, e));

        // Decrypt
        let decrypted = key
            .decrypt(&ciphertext)
            .unwrap_or_else(|e| panic!("Vector {}: Decryption failed: {}", i, e));

        // Plaintext is stored as raw UTF-8 string (not base64 encoded)
        // Note: Some plaintexts happen to BE base64 strings (random bytes for testing)
        let expected_plaintext = v.plaintext.as_bytes();

        assert_eq!(
            decrypted, expected_plaintext,
            "Symmetric key decryption failed for vector {}",
            i
        );
    }
}

// ============================================================================
// Cross-SDK Compatibility Tests (Go/TypeScript ciphertext)
// ============================================================================

/// Test vectors from Go SDK that TypeScript and Rust should decrypt.
#[test]
fn test_31_byte_key_go_ciphertext_compatibility() {
    // This WIF produces a 31-byte X coordinate
    let priv_key =
        PrivateKey::from_wif("L4B2postXdaP7TiUrUBYs53Fqzheu7WhSoQVPuY8qBdoBeEwbmZx").unwrap();
    let pub_key = priv_key.public_key();

    // Get X coordinate as key bytes
    let key_bytes = pub_key.x();

    // Verify this produces a key that starts with 0 (31-byte effective key)
    assert_eq!(key_bytes[0], 0, "Expected 31-byte key (leading zero)");

    let sym_key = SymmetricKey::from_bytes(&key_bytes).unwrap();
    let expected_plaintext = "cross-sdk test message";

    // Go-generated ciphertexts
    let test_ciphertexts = [
        "7604d5bdb0eb843051d21873c871c9b1507c3de7ba222e1b407c163c2c166277df95de73be9534a2caf9d4b72157f78e5e2e69d97bc25b18ff4cfbd61a1306c02c0b8b2d165e",
        "ab74fa03d7b2d308f007e21fbae056cfde6e3e5fbea7032880e0482b0b5fbe8583d5221b985a8cdfdff1f70c2bb28c9a3149a34dde3b56f54ecd4728d2dd70c1212642b18bc4",
        "6c64ae72a1371084347983568d25515ca75599f747236be6971267fa4b48e518855ce4f8380cc479bb75835641f2173b7932b93be5cd40f54cd84aaff053dbc94c3748e427af",
    ];

    for (i, ct_hex) in test_ciphertexts.iter().enumerate() {
        let ciphertext = from_hex(ct_hex).unwrap();
        let decrypted = sym_key.decrypt(&ciphertext).unwrap_or_else(|e| {
            panic!("31-byte key Go ciphertext {}: decryption failed: {}", i, e)
        });

        let decrypted_str = String::from_utf8(decrypted).unwrap();
        assert_eq!(
            decrypted_str, expected_plaintext,
            "31-byte key Go ciphertext {} decryption mismatch",
            i
        );
    }
}

#[test]
fn test_32_byte_key_go_ciphertext_compatibility() {
    // This WIF produces a 32-byte X coordinate
    let priv_key =
        PrivateKey::from_wif("KyLGEhYicSoGchHKmVC2fUx2MRrHzWqvwBFLLT4DZB93Nv5DxVR9").unwrap();
    let pub_key = priv_key.public_key();

    // Get X coordinate as key bytes
    let key_bytes = pub_key.x();

    // Verify this is a full 32-byte key (no leading zero needed)
    assert_ne!(key_bytes[0], 0, "Expected 32-byte key (no leading zero)");

    let sym_key = SymmetricKey::from_bytes(&key_bytes).unwrap();
    let expected_plaintext = "cross-sdk test message";

    // Go-generated ciphertexts
    let test_ciphertexts = [
        "d7744c85ad3dafcb9fc5752ab0d04c40f87084e8a466f6b6013ebe0fc5170daab8184aaef66ab2c2733f01c0dc3de322ba3ddeea976499548bc6ec166581181f919c69aa2de5",
        "bed1fc660bb7219d05a0115bc3c8dfb063fceb07c6571e0a21af1a052988dfd8911f625ae747ae6dad4cadb872dbd1d1bdc4b78bf7817e90bc5df718d77b247805eb06773d13",
        "7411f0e9ff2b6ebbb804614fcf11db548a92baeea9cd769e8ee11bd7853a2d055799df476655b7d30f11be17f9513a16b72b6c73f85edd4b6e7548fae68fb47252ff72ace4cf",
    ];

    for (i, ct_hex) in test_ciphertexts.iter().enumerate() {
        let ciphertext = from_hex(ct_hex).unwrap();
        let decrypted = sym_key.decrypt(&ciphertext).unwrap_or_else(|e| {
            panic!("32-byte key Go ciphertext {}: decryption failed: {}", i, e)
        });

        let decrypted_str = String::from_utf8(decrypted).unwrap();
        assert_eq!(
            decrypted_str, expected_plaintext,
            "32-byte key Go ciphertext {} decryption mismatch",
            i
        );
    }
}

#[test]
fn test_typescript_ciphertext_compatibility() {
    // Test TypeScript-generated ciphertexts

    // 31-byte key TypeScript ciphertext
    let priv_key_31 =
        PrivateKey::from_wif("L4B2postXdaP7TiUrUBYs53Fqzheu7WhSoQVPuY8qBdoBeEwbmZx").unwrap();
    let sym_key_31 = SymmetricKey::from_bytes(&priv_key_31.public_key().x()).unwrap();

    let ts_ciphertext_31 = "c374d70a4623036f1dd7b971dbeeea375630dc1da40e7068f4c4aa03487d3b19de3afb26a29173deccfbb1ece4fee6c92406b25948e6fe9cb53383057cb826d0a20269e290bd";
    let ciphertext = from_hex(ts_ciphertext_31).unwrap();
    let decrypted = sym_key_31.decrypt(&ciphertext).unwrap();
    assert_eq!(
        String::from_utf8(decrypted).unwrap(),
        "cross-sdk test message"
    );

    // 32-byte key TypeScript ciphertext
    let priv_key_32 =
        PrivateKey::from_wif("KyLGEhYicSoGchHKmVC2fUx2MRrHzWqvwBFLLT4DZB93Nv5DxVR9").unwrap();
    let sym_key_32 = SymmetricKey::from_bytes(&priv_key_32.public_key().x()).unwrap();

    let ts_ciphertext_32 = "2059fc32910bef280d89c4c7edbbc587b31be22339e609fdcc23319bf458840a91ad1b2da87aea13a5dc5cb3469b41c52001070b8003863843978acbdf57755b24491581a059";
    let ciphertext = from_hex(ts_ciphertext_32).unwrap();
    let decrypted = sym_key_32.decrypt(&ciphertext).unwrap();
    assert_eq!(
        String::from_utf8(decrypted).unwrap(),
        "cross-sdk test message"
    );
}

#[test]
fn test_rust_encryption_roundtrip_with_31_byte_key() {
    // Verify Rust can encrypt and decrypt with 31-byte keys
    let priv_key =
        PrivateKey::from_wif("L4B2postXdaP7TiUrUBYs53Fqzheu7WhSoQVPuY8qBdoBeEwbmZx").unwrap();
    let key_bytes = priv_key.public_key().x();

    let sym_key = SymmetricKey::from_bytes(&key_bytes).unwrap();

    let plaintext = b"cross-sdk test message";
    let ciphertext = sym_key.encrypt(plaintext).unwrap();
    let decrypted = sym_key.decrypt(&ciphertext).unwrap();

    assert_eq!(plaintext.as_slice(), decrypted.as_slice());
}

#[test]
fn test_rust_encryption_roundtrip_with_32_byte_key() {
    // Verify Rust can encrypt and decrypt with 32-byte keys
    let priv_key =
        PrivateKey::from_wif("KyLGEhYicSoGchHKmVC2fUx2MRrHzWqvwBFLLT4DZB93Nv5DxVR9").unwrap();
    let key_bytes = priv_key.public_key().x();

    let sym_key = SymmetricKey::from_bytes(&key_bytes).unwrap();

    let plaintext = b"cross-sdk test message";
    let ciphertext = sym_key.encrypt(plaintext).unwrap();
    let decrypted = sym_key.decrypt(&ciphertext).unwrap();

    assert_eq!(plaintext.as_slice(), decrypted.as_slice());
}

// ============================================================================
// WIF Compatibility Tests
// ============================================================================

#[test]
fn test_wif_compatibility_vectors() {
    // Known WIF test vectors from Bitcoin/BSV
    let test_cases = [
        (
            "5HueCGU8rMjxEXxiPuD5BDku4MkFqeZyd4dZ1jvhTVqvbTLvyTJ",
            "0c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d",
            false, // uncompressed
        ),
        (
            "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn",
            "0000000000000000000000000000000000000000000000000000000000000001",
            true, // compressed
        ),
        (
            "KxFC1jmwwCoACiCAWZ3eXa96mBM6tb3TYzGmf6YwgdGWZgawvrtJ",
            "1e99423a4ed27608a15a2616a2b0e9e52ced330ac530edcc32c8ffc6a526aedd",
            true, // compressed
        ),
    ];

    for (wif, expected_hex, is_compressed) in test_cases {
        let key = PrivateKey::from_wif(wif)
            .unwrap_or_else(|e| panic!("Failed to parse WIF '{}': {}", wif, e));

        assert_eq!(
            key.to_hex(),
            expected_hex,
            "WIF '{}' produced wrong private key",
            wif
        );

        // For compressed WIFs, roundtrip should work
        if is_compressed {
            assert_eq!(key.to_wif(), wif, "WIF roundtrip failed for '{}'", wif);
        }
    }
}

#[test]
fn test_public_key_compatibility_vectors() {
    // Known private key -> public key vectors
    let test_cases = [
        (
            "0000000000000000000000000000000000000000000000000000000000000001",
            "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
        ),
        (
            "0000000000000000000000000000000000000000000000000000000000000002",
            "02c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5",
        ),
        (
            "0000000000000000000000000000000000000000000000000000000000000003",
            "02f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9",
        ),
    ];

    for (priv_hex, expected_pub_hex) in test_cases {
        let priv_key = PrivateKey::from_hex(priv_hex).unwrap();
        let pub_key = priv_key.public_key();

        assert_eq!(
            pub_key.to_hex(),
            expected_pub_hex,
            "Public key mismatch for private key {}",
            priv_hex
        );
    }
}

#[test]
fn test_address_compatibility_vectors() {
    // Known public key -> address vectors
    let test_cases = [
        // Generator point (private key 1)
        (
            "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
            "1BgGZ9tcN4rm9KBzDn7KprQz87SZ26SAMH",
        ),
    ];

    for (pub_hex, expected_address) in test_cases {
        let pub_key = PublicKey::from_hex(pub_hex).unwrap();
        let address = pub_key.to_address();

        assert_eq!(
            address, expected_address,
            "Address mismatch for public key {}",
            pub_hex
        );
    }
}

// ============================================================================
// DRBG Vectors (for signature determinism verification)
// ============================================================================

#[test]
fn test_drbg_vectors_loaded() {
    // Verify DRBG vectors can be loaded and parsed
    let vectors = load_drbg_vectors();
    assert!(!vectors.is_empty(), "DRBG vectors should not be empty");
    assert_eq!(vectors.len(), 15, "Expected 15 DRBG vectors");

    // Verify structure of first vector
    let first = &vectors[0];
    assert_eq!(first.name, "0");
    assert_eq!(first.entropy.len(), 64); // 32 bytes hex
    assert_eq!(first.nonce.len(), 32); // 16 bytes hex
    assert_eq!(first.expected.len(), 256); // 128 bytes hex (HMAC-DRBG output)
}

// ============================================================================
// Unicode and Special Characters
// ============================================================================

#[test]
fn test_symmetric_encryption_unicode() {
    // Test encryption/decryption of Unicode text (from TypeScript test vectors)
    let key = SymmetricKey::random();

    let test_strings = [
        "Hello, World!",
        "Hallo, Welt!",
        "Bonjour, le monde!",
        "Ciao, mondo!",
        "\u{00fc}\u{00f1}\u{00ee}\u{00e7}\u{00f8}\u{2202}\u{00e9}", // Unicode chars
        "",
        "A cat and a mouse.",
    ];

    for plaintext in test_strings {
        let ciphertext = key.encrypt(plaintext.as_bytes()).unwrap();
        let decrypted = key.decrypt(&ciphertext).unwrap();

        assert_eq!(
            String::from_utf8(decrypted).unwrap(),
            plaintext,
            "Unicode roundtrip failed for: {}",
            plaintext
        );
    }
}

// ============================================================================
// Edge Cases
// ============================================================================

#[test]
fn test_empty_message_encryption() {
    let key = SymmetricKey::random();
    let plaintext = b"";

    let ciphertext = key.encrypt(plaintext).unwrap();
    let decrypted = key.decrypt(&ciphertext).unwrap();

    assert!(decrypted.is_empty());
}

#[test]
fn test_large_message_encryption() {
    let key = SymmetricKey::random();
    let plaintext = vec![0xab; 1024 * 1024]; // 1 MB

    let ciphertext = key.encrypt(&plaintext).unwrap();
    let decrypted = key.decrypt(&ciphertext).unwrap();

    assert_eq!(plaintext, decrypted);
}

#[test]
fn test_brc42_empty_invoice() {
    // Empty invoice number should still produce valid derivation
    // BRC-42: recipient derives child private key, sender derives matching public key
    let sender = PrivateKey::random();
    let recipient = PrivateKey::random();

    // Recipient derives child private key from sender's public key
    let recipient_child = recipient.derive_child(&sender.public_key(), "").unwrap();
    // Sender derives the corresponding public key from recipient's public key
    let sender_derived_pub = recipient.public_key().derive_child(&sender, "").unwrap();

    assert_eq!(
        recipient_child.public_key().to_compressed(),
        sender_derived_pub.to_compressed()
    );
}

#[test]
fn test_brc42_long_invoice() {
    // Long invoice numbers should work
    let sender = PrivateKey::random();
    let recipient = PrivateKey::random();

    let long_invoice = "x".repeat(1000);

    // Recipient derives child private key from sender's public key
    let recipient_child = recipient
        .derive_child(&sender.public_key(), &long_invoice)
        .unwrap();
    // Sender derives the corresponding public key from recipient's public key
    let sender_derived_pub = recipient
        .public_key()
        .derive_child(&sender, &long_invoice)
        .unwrap();

    assert_eq!(
        recipient_child.public_key().to_compressed(),
        sender_derived_pub.to_compressed()
    );
}
