pub mod engine;
pub mod hmac_index;
pub mod key_manager;
pub mod masking;

pub use engine::{decrypt, encrypt};
pub use hmac_index::hmac_hash;
pub use key_manager::DekManager;
pub use masking::{mask_id_number, mask_license_number, mask_phone};

use crate::error::{AppError, AppResult};

/// PII 加密服务 — 封装 KEK 和 DEK 管理
#[derive(Clone)]
pub struct PiiCrypto {
    kek: [u8; 32],
    hmac_key: [u8; 32],
    pub(crate) dek_manager: DekManager,
}

impl PiiCrypto {
    /// 从 hex 编码的 KEK 创建。KEK 为 64 字符 hex（32 字节）。
    pub fn from_kek_hex(kek_hex: &str) -> AppResult<Self> {
        let bytes = hex::decode(kek_hex)
            .map_err(|e| AppError::Internal(format!("KEK hex decode failed: {}", e)))?;
        if bytes.len() != 32 {
            return Err(AppError::Internal(
                "KEK must be 32 bytes (64 hex chars)".into(),
            ));
        }
        let mut kek = [0u8; 32];
        kek.copy_from_slice(&bytes);
        Ok(Self::from_kek(kek))
    }

    /// Dev fallback: 从固定字符串派生确定性 KEK。仅用于开发。
    pub fn dev_default() -> Self {
        use sha2::Digest;
        let kek = <sha2::Sha256 as Digest>::digest(b"erp-pii-kek-dev-key-DO-NOT-USE-IN-PROD");
        let mut key = [0u8; 32];
        key.copy_from_slice(&kek);
        Self::from_kek(key)
    }

    fn from_kek(kek: [u8; 32]) -> Self {
        use sha2::Digest;
        let hmac_key = <sha2::Sha256 as Digest>::new()
            .chain_update(b"pii-hmac-index-v1")
            .chain_update(kek)
            .finalize();
        let mut hk = [0u8; 32];
        hk.copy_from_slice(&hmac_key);
        Self {
            kek,
            hmac_key: hk,
            dek_manager: DekManager::new(300, 100),
        }
    }

    pub fn kek(&self) -> &[u8; 32] {
        &self.kek
    }

    /// HMAC 搜索索引使用的独立子密钥
    pub fn hmac_key(&self) -> &[u8; 32] {
        &self.hmac_key
    }

    /// 使指定租户的 DEK 缓存失效
    pub fn invalidate_dek(&self, tenant_id: uuid::Uuid) {
        self.dek_manager.invalidate(tenant_id);
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    fn test_crypto() -> PiiCrypto {
        PiiCrypto::dev_default()
    }

    #[test]
    fn from_kek_hex_roundtrip() {
        let kek_hex = "00".repeat(32);
        let crypto = PiiCrypto::from_kek_hex(&kek_hex).unwrap();
        assert_eq!(crypto.kek(), &[0u8; 32]);
    }

    #[test]
    fn from_kek_hex_invalid() {
        assert!(PiiCrypto::from_kek_hex("not-hex").is_err());
    }

    #[test]
    fn from_kek_hex_wrong_length() {
        assert!(PiiCrypto::from_kek_hex("ab").is_err());
    }

    #[test]
    fn encrypt_decrypt_roundtrip() {
        let crypto = test_crypto();
        let plaintext = "13812345678";
        let encrypted = encrypt(crypto.kek(), plaintext).unwrap();
        let decrypted = decrypt(crypto.kek(), &encrypted).unwrap();
        assert_eq!(plaintext, decrypted);
    }

    #[test]
    fn encrypt_produces_different_ciphertexts() {
        let crypto = test_crypto();
        let e1 = encrypt(crypto.kek(), "test").unwrap();
        let e2 = encrypt(crypto.kek(), "test").unwrap();
        assert_ne!(e1, e2);
    }

    #[test]
    fn decrypt_wrong_key_fails() {
        let crypto1 = PiiCrypto::dev_default();
        let other_key_hex = "ff".repeat(32);
        let crypto2 = PiiCrypto::from_kek_hex(&other_key_hex).unwrap();
        let encrypted = encrypt(crypto1.kek(), "test").unwrap();
        assert!(decrypt(crypto2.kek(), &encrypted).is_err());
    }

    #[test]
    fn hmac_hash_deterministic() {
        let crypto = test_crypto();
        let h1 = hmac_hash(crypto.hmac_key(), "13812345678");
        let h2 = hmac_hash(crypto.hmac_key(), "13812345678");
        assert_eq!(h1, h2);
    }

    #[test]
    fn hmac_hash_different_inputs() {
        let crypto = test_crypto();
        let h1 = hmac_hash(crypto.hmac_key(), "111");
        let h2 = hmac_hash(crypto.hmac_key(), "222");
        assert_ne!(h1, h2);
    }

    #[test]
    fn hmac_key_differs_from_kek() {
        let crypto = test_crypto();
        assert_ne!(crypto.kek(), crypto.hmac_key(), "HMAC 密钥应与 KEK 不同");
    }

    #[test]
    fn encrypt_empty_string() {
        let crypto = test_crypto();
        let encrypted = encrypt(crypto.kek(), "").unwrap();
        let decrypted = decrypt(crypto.kek(), &encrypted).unwrap();
        assert_eq!("", decrypted);
    }

    #[test]
    fn decrypt_too_short_fails() {
        use base64::Engine;
        let short = base64::engine::general_purpose::STANDARD.encode(b"short");
        assert!(decrypt(&[0u8; 32], &short).is_err());
    }

    #[test]
    fn encrypt_unicode() {
        let crypto = test_crypto();
        let plaintext = "患者过敏史：青霉素、磺胺类药物";
        let encrypted = encrypt(crypto.kek(), plaintext).unwrap();
        let decrypted = decrypt(crypto.kek(), &encrypted).unwrap();
        assert_eq!(plaintext, decrypted);
    }

    #[test]
    fn ciphertext_has_version_prefix() {
        let crypto = test_crypto();
        let encrypted = encrypt(crypto.kek(), "test").unwrap();
        use base64::Engine;
        let bytes = base64::engine::general_purpose::STANDARD
            .decode(&encrypted)
            .unwrap();
        assert_eq!(bytes[0], 0x01, "密文首字节应为版本号 0x01");
    }

    // ── 性能基准 ──

    #[test]
    fn bench_encrypt_1000() {
        let crypto = test_crypto();
        let kek = crypto.kek();
        let plaintext = "13812345678";
        let start = std::time::Instant::now();
        for _ in 0..1000 {
            let _ = encrypt(kek, plaintext).unwrap();
        }
        let elapsed = start.elapsed();
        let avg_us = elapsed.as_micros() / 1000;
        assert!(avg_us < 50, "encrypt 平均耗时应 < 50μs, 实际: {}μs", avg_us);
        eprintln!("encrypt 1000 次: {:?} (avg {}μs)", elapsed, avg_us);
    }

    #[test]
    fn bench_decrypt_1000() {
        let crypto = test_crypto();
        let kek = crypto.kek();
        let ciphertext = encrypt(kek, "13812345678").unwrap();
        let start = std::time::Instant::now();
        for _ in 0..1000 {
            let _ = decrypt(kek, &ciphertext).unwrap();
        }
        let elapsed = start.elapsed();
        let avg_us = elapsed.as_micros() / 1000;
        assert!(avg_us < 50, "decrypt 平均耗时应 < 50μs, 实际: {}μs", avg_us);
        eprintln!("decrypt 1000 次: {:?} (avg {}μs)", elapsed, avg_us);
    }

    #[test]
    fn bench_batch_decrypt_50() {
        let crypto = test_crypto();
        let kek = crypto.kek();
        let ciphertexts: Vec<String> = (0..50)
            .map(|i| encrypt(kek, &format!("数据{}", i)).unwrap())
            .collect();
        let start = std::time::Instant::now();
        for ct in &ciphertexts {
            let _ = decrypt(kek, ct).unwrap();
        }
        let elapsed = start.elapsed();
        assert!(
            elapsed.as_millis() < 10,
            "批量解密 50 条应 < 10ms, 实际: {}ms",
            elapsed.as_millis()
        );
        eprintln!("batch decrypt 50 条: {:?}", elapsed);
    }
}
