package com.rosetta.messenger.crypto

import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Test
import org.junit.Assert.*
import org.junit.Before
import org.junit.runner.RunWith

/**
 * 🧪 Тесты кросс-платформенной совместимости шифрования
 * 
 * Проверяют совместимость между:
 * - Kotlin (CryptoManager.kt)
 * - JS/React Native (cryptoJSI.ts)
 * 
 * Алгоритм:
 * - PBKDF2-HMAC-SHA1 (1000 iterations, salt="rosetta")
 * - AES-256-CBC + PKCS7 padding
 * - zlib compression (deflate/inflate)
 * - Format: base64(iv):base64(ciphertext)
 */
@RunWith(AndroidJUnit4::class)
class CryptoCompatibilityTest {
    
    @Before
    fun setup() {
        java.security.Security.addProvider(org.bouncycastle.jce.provider.BouncyCastleProvider())
    }
    
    // ========================================
    // 🔐 Тестовые данные, зашифрованные на JS
    // ========================================
    
    /**
     * Эти данные были зашифрованы на JS (cryptoJSI.ts):
     * 
     * const encrypted = encodeWithPasswordJSI("testPassword123", "Hello World");
     * console.log(encrypted);
     * 
     * Параметры:
     * - password: "testPassword123"
     * - plaintext: "Hello World"
     * - salt: "rosetta"
     * - iterations: 1000
     * - hash: SHA1
     */
    companion object {
        // ⚠️ TODO: Вставьте реальные зашифрованные данные из JS консоли
        // Для генерации выполните в RN/JS:
        //
        // import { encodeWithPasswordJSI } from './cryptoJSI';
        // console.log('Test 1:', encodeWithPasswordJSI("testPassword123", "Hello World"));
        // console.log('Test 2:', encodeWithPasswordJSI("mySecretPass", '{"key":"value","number":42}'));
        // console.log('Test 3:', encodeWithPasswordJSI("password", ""));
        // console.log('Test 4:', encodeWithPasswordJSI("пароль123", "Привет мир! 🔐"));
        
        // Placeholder - замените реальными данными из JS
        const val JS_ENCRYPTED_HELLO_WORLD = "" // encodeWithPasswordJSI("testPassword123", "Hello World")
        const val JS_ENCRYPTED_JSON = ""        // encodeWithPasswordJSI("mySecretPass", '{"key":"value","number":42}')
        const val JS_ENCRYPTED_EMPTY = ""       // encodeWithPasswordJSI("password", "")
        const val JS_ENCRYPTED_CYRILLIC = ""    // encodeWithPasswordJSI("пароль123", "Привет мир! 🔐")
    }
    
    // ========================================
    // ✅ Тесты Kotlin → Kotlin (базовая проверка)
    // ========================================
    
    @Test
    fun kotlin_encrypt_decrypt_roundtrip() {
        val originalData = "Hello, World! This is a secret message."
        val password = "testPassword123"
        
        val encrypted = CryptoManager.encryptWithPassword(originalData, password)
        val decrypted = CryptoManager.decryptWithPassword(encrypted, password)
        
        assertNotNull("Encrypted data should not be null", encrypted)
        assertTrue("Encrypted should contain ':'", encrypted.contains(":"))
        assertEquals("Decrypted should match original", originalData, decrypted)
    }
    
    @Test
    fun kotlin_encrypt_decrypt_empty_string() {
        val originalData = ""
        val password = "password"
        
        val encrypted = CryptoManager.encryptWithPassword(originalData, password)
        val decrypted = CryptoManager.decryptWithPassword(encrypted, password)
        
        assertEquals("Empty string should roundtrip correctly", originalData, decrypted)
    }
    
    @Test
    fun kotlin_encrypt_decrypt_cyrillic_and_emoji() {
        val originalData = "Привет мир! 🔐 Тест кириллицы и эмодзи 🚀"
        val password = "пароль123"
        
        val encrypted = CryptoManager.encryptWithPassword(originalData, password)
        val decrypted = CryptoManager.decryptWithPassword(encrypted, password)
        
        assertEquals("Cyrillic and emoji should roundtrip correctly", originalData, decrypted)
    }
    
    @Test
    fun kotlin_encrypt_decrypt_json() {
        val originalData = """{"key":"value","number":42,"nested":{"array":[1,2,3]}}"""
        val password = "jsonPassword"
        
        val encrypted = CryptoManager.encryptWithPassword(originalData, password)
        val decrypted = CryptoManager.decryptWithPassword(encrypted, password)
        
        assertEquals("JSON should roundtrip correctly", originalData, decrypted)
    }
    
    @Test
    fun kotlin_wrong_password_returns_null() {
        val originalData = "Secret message"
        val correctPassword = "correctPassword"
        val wrongPassword = "wrongPassword"
        
        val encrypted = CryptoManager.encryptWithPassword(originalData, correctPassword)
        val decrypted = CryptoManager.decryptWithPassword(encrypted, wrongPassword)
        
        assertNull("Wrong password should return null", decrypted)
    }
    
    // ========================================
    // 🌐 Тесты JS → Kotlin (кросс-платформа)
    // ========================================
    
    @Test
    fun js_to_kotlin_decrypt_hello_world() {
        if (JS_ENCRYPTED_HELLO_WORLD.isEmpty()) {
            println("⚠️ SKIP: JS_ENCRYPTED_HELLO_WORLD not set. Generate from JS first.")
            return
        }
        
        val decrypted = CryptoManager.decryptWithPassword(JS_ENCRYPTED_HELLO_WORLD, "testPassword123")
        
        assertEquals("Should decrypt JS data correctly", "Hello World", decrypted)
    }
    
    @Test
    fun js_to_kotlin_decrypt_json() {
        if (JS_ENCRYPTED_JSON.isEmpty()) {
            println("⚠️ SKIP: JS_ENCRYPTED_JSON not set. Generate from JS first.")
            return
        }
        
        val decrypted = CryptoManager.decryptWithPassword(JS_ENCRYPTED_JSON, "mySecretPass")
        
        assertEquals("Should decrypt JSON from JS", """{"key":"value","number":42}""", decrypted)
    }
    
    @Test
    fun js_to_kotlin_decrypt_empty() {
        if (JS_ENCRYPTED_EMPTY.isEmpty()) {
            println("⚠️ SKIP: JS_ENCRYPTED_EMPTY not set. Generate from JS first.")
            return
        }
        
        val decrypted = CryptoManager.decryptWithPassword(JS_ENCRYPTED_EMPTY, "password")
        
        assertEquals("Should decrypt empty string from JS", "", decrypted)
    }
    
    @Test
    fun js_to_kotlin_decrypt_cyrillic() {
        if (JS_ENCRYPTED_CYRILLIC.isEmpty()) {
            println("⚠️ SKIP: JS_ENCRYPTED_CYRILLIC not set. Generate from JS first.")
            return
        }
        
        val decrypted = CryptoManager.decryptWithPassword(JS_ENCRYPTED_CYRILLIC, "пароль123")
        
        assertEquals("Should decrypt Cyrillic from JS", "Привет мир! 🔐", decrypted)
    }
    
    // ========================================
    // 🔧 Тест формата данных
    // ========================================
    
    @Test
    fun encrypted_format_is_correct() {
        val encrypted = CryptoManager.encryptWithPassword("test", "password")
        
        val parts = encrypted.split(":")
        assertEquals("Should have exactly 2 parts (iv:ct)", 2, parts.size)
        
        // Проверяем что обе части - валидный Base64
        try {
            val iv = android.util.Base64.decode(parts[0], android.util.Base64.NO_WRAP)
            val ct = android.util.Base64.decode(parts[1], android.util.Base64.NO_WRAP)
            
            assertEquals("IV should be 16 bytes", 16, iv.size)
            assertTrue("Ciphertext should not be empty", ct.isNotEmpty())
        } catch (e: Exception) {
            fail("Both parts should be valid Base64: ${e.message}")
        }
    }
    
    // ========================================
    // 📊 Тест PBKDF2 ключа (для отладки)
    // ========================================
    
    @Test
    fun pbkdf2_key_derivation_is_correct() {
        // Известный тестовый вектор для PBKDF2-HMAC-SHA1
        // password: "testPassword123", salt: "rosetta", iterations: 1000, keyLen: 32
        
        val factory = javax.crypto.SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1")
        val spec = javax.crypto.spec.PBEKeySpec(
            "testPassword123".toCharArray(),
            "rosetta".toByteArray(Charsets.UTF_8),
            1000,
            256
        )
        val key = factory.generateSecret(spec).encoded
        
        // Выводим ключ для сравнения с JS
        val keyHex = key.joinToString("") { "%02x".format(it) }
        println("🔑 PBKDF2 Key (hex): $keyHex")
        
        assertEquals("Key should be 32 bytes", 32, key.size)
        
        // ⚠️ TODO: Сравните этот ключ с JS:
        // const key = generatePBKDF2KeyJSI("testPassword123");
        // console.log("Key (hex):", key.toString('hex'));
    }
}
