use portable_toolkit::cipher::{decrypt_bytes, decrypt_file, encrypt_bytes, encrypt_file, validate_key};
use std::fs;
use std::path::PathBuf;

// ── validate_key ──────────────────────────────────────────────────────────────

#[test]
fn test_validate_key_valid_16_bytes() {
    let result = validate_key("1234567890123456");
    assert!(result.is_ok());
    assert_eq!(result.unwrap(), *b"1234567890123456");
}

#[test]
fn test_validate_key_too_short_returns_error() {
    let result = validate_key("short");
    assert!(result.is_err());
    assert!(result.unwrap_err().contains("密钥长度无效"));
}

#[test]
fn test_validate_key_too_long_returns_error() {
    let result = validate_key("12345678901234567");
    assert!(result.is_err());
    assert!(result.unwrap_err().contains("密钥长度无效"));
}

#[test]
fn test_validate_key_empty_returns_error() {
    let result = validate_key("");
    assert!(result.is_err());
}

// ── encrypt_bytes / decrypt_bytes ─────────────────────────────────────────────

#[test]
fn test_encrypt_decrypt_bytes_roundtrip() {
    let key = b"1234567890123456";
    let plain = b"Hello, AES-GCM!";

    let encrypted = encrypt_bytes(plain, key).unwrap();
    // 密文长度 = 12(nonce) + 原文长度 + 16(GCM tag)
    assert_eq!(encrypted.len(), 12 + plain.len() + 16);

    let decrypted = decrypt_bytes(&encrypted, key).unwrap();
    assert_eq!(decrypted, plain);
}

#[test]
fn test_encrypt_same_plaintext_produces_different_ciphertext() {
    let key = b"1234567890123456";
    let plain = b"same plaintext";

    let enc1 = encrypt_bytes(plain, key).unwrap();
    let enc2 = encrypt_bytes(plain, key).unwrap();
    // nonce 随机，密文应不同
    assert_ne!(enc1, enc2);
    // 但解密结果相同
    assert_eq!(decrypt_bytes(&enc1, key).unwrap(), plain);
    assert_eq!(decrypt_bytes(&enc2, key).unwrap(), plain);
}

#[test]
fn test_decrypt_with_wrong_key_returns_error() {
    let key = b"1234567890123456";
    let wrong_key = b"abcdefghijklmnop";
    let plain = b"secret data";

    let encrypted = encrypt_bytes(plain, key).unwrap();
    let result = decrypt_bytes(&encrypted, wrong_key);
    assert!(result.is_err());
    assert!(result.unwrap_err().contains("解密失败"));
}

#[test]
fn test_decrypt_too_short_ciphertext_returns_error() {
    let key = b"1234567890123456";
    let too_short = b"short";
    let result = decrypt_bytes(too_short, key);
    assert!(result.is_err());
    assert!(result.unwrap_err().contains("密文长度无效"));
}

#[test]
fn test_encrypt_decrypt_empty_bytes() {
    let key = b"1234567890123456";
    let plain: &[u8] = b"";

    let encrypted = encrypt_bytes(plain, key).unwrap();
    let decrypted = decrypt_bytes(&encrypted, key).unwrap();
    assert_eq!(decrypted, plain);
}

#[test]
fn test_encrypt_decrypt_large_data() {
    let key = b"1234567890123456";
    let plain = vec![0xABu8; 1024 * 1024]; // 1 MB

    let encrypted = encrypt_bytes(&plain, key).unwrap();
    let decrypted = decrypt_bytes(&encrypted, key).unwrap();
    assert_eq!(decrypted, plain);
}

// ── encrypt_file / decrypt_file ───────────────────────────────────────────────

#[test]
fn test_encrypt_decrypt_file_roundtrip() {
    let dir = tempdir();
    let input = dir.join("plain.txt");
    let encrypted = dir.join("cipher.bin");
    let output = dir.join("result.txt");

    let content = b"file content for testing";
    fs::write(&input, content).unwrap();

    encrypt_file(&input, &encrypted, "1234567890123456").unwrap();
    decrypt_file(&encrypted, &output, "1234567890123456").unwrap();

    assert_eq!(fs::read(&output).unwrap(), content);
}

#[test]
fn test_encrypt_nonexistent_file_returns_error() {
    let dir = tempdir();
    let result = encrypt_file(
        &dir.join("nonexistent.txt"),
        &dir.join("out.bin"),
        "1234567890123456",
    );
    assert!(result.is_err());
    assert!(result.unwrap_err().contains("读取输入文件失败"));
}

#[test]
fn test_decrypt_file_with_wrong_key_returns_error() {
    let dir = tempdir();
    let input = dir.join("plain.txt");
    let encrypted = dir.join("cipher.bin");
    let output = dir.join("result.txt");

    fs::write(&input, b"secret").unwrap();
    encrypt_file(&input, &encrypted, "1234567890123456").unwrap();

    let result = decrypt_file(&encrypted, &output, "abcdefghijklmnop");
    assert!(result.is_err());
}

#[test]
fn test_encrypt_file_creates_output_directory() {
    let dir = tempdir();
    let input = dir.join("plain.txt");
    let encrypted = dir.join("subdir/nested/cipher.bin");
    let output = dir.join("subdir/nested/result.txt");

    fs::write(&input, b"hello").unwrap();
    encrypt_file(&input, &encrypted, "1234567890123456").unwrap();
    decrypt_file(&encrypted, &output, "1234567890123456").unwrap();

    assert_eq!(fs::read(&output).unwrap(), b"hello");
}

// ── 辅助函数 ──────────────────────────────────────────────────────────────────

fn tempdir() -> PathBuf {
    let path = std::env::temp_dir().join(format!(
        "file_cipher_test_{}",
        std::time::SystemTime::now()
            .duration_since(std::time::UNIX_EPOCH)
            .unwrap()
            .subsec_nanos()
    ));
    fs::create_dir_all(&path).unwrap();
    path
}
