package com.flashlink.vpn

import android.util.Base64
import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
import java.nio.charset.StandardCharsets
import java.util.zip.GZIPInputStream
import java.util.zip.GZIPOutputStream
import javax.crypto.Cipher
import javax.crypto.spec.IvParameterSpec
import javax.crypto.spec.SecretKeySpec

/**
 * 加密工具类 - Kotlin 优化版本
 */
object CryptoUtils {
    private const val TAG = "CryptoUtils"
    private const val AES_ALGORITHM = "AES/CTR/NoPadding"
    private const val AES_KEY_ALGORITHM = "AES"
    private const val BUFFER_SIZE = 8192
    private const val GZIP_BUFFER_SIZE = 1024

    private fun validateParams(key: String, iv: String) {
        require(key.isNotEmpty()) { "Key cannot be null or empty" }
        require(iv.isNotEmpty()) { "IV cannot be null or empty" }
    }

    private fun encryptBytes(data: ByteArray, key: String, iv: String): ByteArray {
        require(data.isNotEmpty()) { "Data cannot be null or empty" }
        validateParams(key, iv)

        return try {
            val keyBytes = Base64.decode(key, Base64.DEFAULT)
            val ivBytes = Base64.decode(iv, Base64.DEFAULT)

            require(keyBytes.size in listOf(16, 24, 32)) { "Invalid key length: ${keyBytes.size}" }
            require(ivBytes.size == 16) { "Invalid IV length: ${ivBytes.size}" }

            val secretKey = SecretKeySpec(keyBytes, AES_KEY_ALGORITHM)
            val ivSpec = IvParameterSpec(ivBytes)

            val cipher = Cipher.getInstance(AES_ALGORITHM)
            cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec)

            cipher.doFinal(data)
        } catch (e: IllegalArgumentException) {
            throw e
        } catch (e: Exception) {
            VLog.e(TAG, "Encryption failed: ${e.message}")
            throw RuntimeException("Encryption failed", e)
        }
    }

    private fun decryptBytes(encryptedData: ByteArray, key: String, iv: String): ByteArray {
        require(encryptedData.isNotEmpty()) { "Encrypted data cannot be null or empty" }
        validateParams(key, iv)

        return try {
            val keyBytes = Base64.decode(key, Base64.DEFAULT)
            val ivBytes = Base64.decode(iv, Base64.DEFAULT)

            val secretKey = SecretKeySpec(keyBytes, AES_KEY_ALGORITHM)
            val ivSpec = IvParameterSpec(ivBytes)

            val cipher = Cipher.getInstance(AES_ALGORITHM)
            cipher.init(Cipher.DECRYPT_MODE, secretKey, ivSpec)

            cipher.doFinal(encryptedData)
        } catch (e: IllegalArgumentException) {
            throw e
        } catch (e: Exception) {
            VLog.e(TAG, "Decryption failed: ${e.message}")
            throw RuntimeException("Decryption failed", e)
        }
    }

    private fun compressBytes(data: ByteArray?): ByteArray? {
        if (data == null || data.isEmpty()) {
            return data
        }

        return try {
            ByteArrayOutputStream(data.size).use { byteStream ->
                GZIPOutputStream(byteStream).use { gzipStream ->
                    gzipStream.write(data)
                    gzipStream.finish()
                }
                byteStream.toByteArray()
            }
        } catch (e: Exception) {
            VLog.e(TAG, "Compression failed: ${e.message}")
            throw RuntimeException("Compression failed", e)
        }
    }

    private fun decompressBytes(compressedData: ByteArray?): ByteArray? {
        if (compressedData == null || compressedData.isEmpty()) {
            return compressedData
        }

        return try {
            ByteArrayInputStream(compressedData).use { byteStream ->
                GZIPInputStream(byteStream, GZIP_BUFFER_SIZE).use { gzipStream ->
                    ByteArrayOutputStream().use { outputStream ->
                        gzipStream.copyTo(outputStream, BUFFER_SIZE)
                        outputStream.toByteArray()
                    }
                }
            }
        } catch (e: Exception) {
            VLog.e(TAG, "Decompression failed: ${e.message}")
            throw RuntimeException("Decompression failed", e)
        }
    }

    fun compressAndEncrypt(text: String, key: String, iv: String): ByteArray {
        require(text.isNotEmpty()) { "Text cannot be null or empty" }
        validateParams(key, iv)

        return try {
            val textBytes = text.toByteArray(StandardCharsets.UTF_8)
            val compressedBytes = compressBytes(textBytes)!!
            encryptBytes(compressedBytes, key, iv)
        } catch (e: IllegalArgumentException) {
            throw e
        } catch (e: Exception) {
            VLog.e(TAG, "Compress and encrypt failed: ${e.message}")
            throw RuntimeException("Compress and encrypt failed", e)
        }
    }

    fun decryptAndDecompress(encryptedData: ByteArray, key: String, iv: String): String {
        require(encryptedData.isNotEmpty()) { "Encrypted data cannot be null or empty" }
        validateParams(key, iv)

        return try {
            val decryptedBytes = decryptBytes(encryptedData, key, iv)
            val decompressedBytes = decompressBytes(decryptedBytes)!!
            String(decompressedBytes, StandardCharsets.UTF_8)
        } catch (e: IllegalArgumentException) {
            throw e
        } catch (e: Exception) {
            VLog.e(TAG, "Decrypt and decompress failed: ${e.message}")
            throw RuntimeException("Decrypt and decompress failed", e)
        }
    }
}

