// SSH加密通道实现（Phase 4）
// 参考OpenSSH cipher.c, mac.c

use aes::Aes256;
use ctr::Ctr128BE;
use hmac::{Hmac, Mac};
use sha2::Sha256;
use std::io::Write;  // 导入Write trait（OpenSSH标准）
use anyhow::{Result, anyhow};
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use log::{info, debug};
use super::crypto::SessionKeys;  // 导入SessionKeys

type Aes256Ctr = Ctr128BE<Aes256>;
type HmacSha256 = Hmac<Sha256>;

/// SSH加密通道管理器（参考OpenSSH struct sshcipher_ctx）
pub struct EncryptionContext {
    pub encryption_key_ctos: Vec<u8>,  // 客户端→服务器加密密钥
    pub encryption_key_stoc: Vec<u8>,  // 服务器→客户端加密密钥
    pub mac_key_ctos: Vec<u8>,         // 客户端→服务器MAC密钥
    pub mac_key_stoc: Vec<u8>,         // 服务器→客户端MAC密钥
    pub sequence_number_ctos: u32,     // 客户端→服务器序列号
    pub sequence_number_stoc: u32,     // 服务器→客户端序列号
}

impl EncryptionContext {
    /// 创建加密上下文（从SessionKeys）
    pub fn from_session_keys(keys: &SessionKeys) -> Self {
        Self {
            encryption_key_ctos: keys.encryption_key_ctos.clone(),
            encryption_key_stoc: keys.encryption_key_stoc.clone(),
            mac_key_ctos: keys.mac_key_ctos.clone(),
            mac_key_stoc: keys.mac_key_stoc.clone(),
            sequence_number_ctos: 0,
            sequence_number_stoc: 0,
        }
    }
    
    /// 加密packet（参考OpenSSH cipher.c: cipher_encrypt()）
    pub fn encrypt_packet(
        &mut self,
        plaintext: &[u8],
        encryption_key: &[u8],
    ) -> Result<Vec<u8>> {
        // AES-256-CTR加密（参考OpenSSH cipher.c）
        // CTR模式不需要padding
        
        // 创建AES-256 cipher（参考OpenSSH）
        let key_array = <[u8; 32]>::try_from(encryption_key)?;
        // TODO: 修复AES初始化（需要使用from_core而不是new）
        // let cipher = Aes256Ctr::new(key_array.into(), <[u8; 16]>::try_from(&[0u8; 16])?);
        
        // 暂时返回plaintext（待修复）
        let mut ciphertext = plaintext.to_vec();
        // cipher.apply_keystream(&mut ciphertext);
        
        // 增加序列号（OpenSSH要求）
        self.sequence_number_stoc += 1;
        
        Ok(ciphertext)
    }
    
    /// 解密packet（参考OpenSSH cipher.c: cipher_decrypt()）
    pub fn decrypt_packet(
        &mut self,
        ciphertext: &[u8],
        encryption_key: &[u8],
    ) -> Result<Vec<u8>> {
        // AES-256-CTR解密（CTR模式双向）
        
        let key_array = <[u8; 32]>::try_from(encryption_key)?;
        // TODO: 修复AES初始化（需要使用from_core而不是new）
        // let cipher = Aes256Ctr::new(key_array.into(), <[u8; 16]>::try_from(&[0u8; 16])?);
        
        // 暂时返回ciphertext（待修复）
        let mut plaintext = ciphertext.to_vec();
        // cipher.apply_keystream(&mut plaintext);
        
        // 增加序列号（OpenSSH要求）
        self.sequence_number_ctos += 1;
        
        Ok(plaintext)
    }
    
    /// 计算MAC（参考OpenSSH mac.c: mac_compute()）
    pub fn compute_mac(
        &self,
        sequence_number: u32,
        data: &[u8],
        mac_key: &[u8],
    ) -> Result<Vec<u8>> {
        // HMAC-SHA256 MAC计算（参考OpenSSH mac.c）
        
        let mut mac = HmacSha256::new_from_slice(mac_key)?;
        
        // OpenSSH MAC格式：sequence_number + data
        mac.update(&sequence_number.to_be_bytes());
        mac.update(data);
        
        let result = mac.finalize();
        Ok(result.into_bytes().to_vec())
    }
    
    /// 验证MAC（参考OpenSSH mac.c: mac_check()）
    pub fn verify_mac(
        &self,
        sequence_number: u32,
        data: &[u8],
        expected_mac: &[u8],
        mac_key: &[u8],
    ) -> Result<bool> {
        // HMAC验证（参考OpenSSH mac.c）
        
        let computed_mac = self.compute_mac(sequence_number, data, mac_key)?;
        
        // 防止时间攻击（使用常量时间比较）
        if computed_mac.len() != expected_mac.len() {
            return Ok(false);
        }
        
        // 简化实现：直接比较（实际应使用常量时间比较）
        Ok(computed_mac == expected_mac)
    }
}

/// SSH加密packet封装（参考OpenSSH packet.c: ssh_packet_write_poll()）
pub struct EncryptedPacket {
    pub packet_length: u32,      // 加密后packet长度
    pub padding_length: u8,      // padding长度（加密后）
    pub payload: Vec<u8>,        // payload（加密后）
    pub padding: Vec<u8>,        // padding（加密后）
    pub mac: Vec<u8>,            // MAC（32字节，HMAC-SHA256）
}

impl EncryptedPacket {
    /// 创建加密packet（参考OpenSSH）
    pub fn new(
        plaintext_payload: &[u8],
        encryption_ctx: &mut EncryptionContext,
        is_server_to_client: bool,
    ) -> Result<Self> {
        // 参考OpenSSH packet.c: construct packet
        
        // 1. 计算padding（加密阶段：block_size = AES block size = 16）
        let block_size = 16;  // AES block size
        let min_padding = 4;
        
        let payload_length = plaintext_payload.len();
        let total_without_mac = 1 + payload_length + min_padding;
        let padding_needed = (block_size - (total_without_mac % block_size)) % block_size;
        let padding_length = std::cmp::max(min_padding, padding_needed as usize) as u8;
        
        // 2. 构建未加密packet（packet_length + padding_length + payload + padding）
        let packet_length = 1 + payload_length + padding_length as usize;
        
        let mut plaintext_packet = Vec::new();
        plaintext_packet.write_u8(padding_length)?;
        plaintext_packet.write_all(plaintext_payload)?;
        plaintext_packet.write_all(&vec![0u8; padding_length as usize])?;
        
        // 3. 加密packet（参考OpenSSH cipher.c）
        let encryption_key = if is_server_to_client {
            encryption_ctx.encryption_key_stoc.clone()  // clone避免borrow冲突
        } else {
            encryption_ctx.encryption_key_ctos.clone()
        };
        
        let encrypted_packet = encryption_ctx.encrypt_packet(&plaintext_packet, &encryption_key)?;
        
        // 4. 计算MAC（参考OpenSSH mac.c）
        let sequence_number = if is_server_to_client {
            encryption_ctx.sequence_number_stoc
        } else {
            encryption_ctx.sequence_number_ctos
        };
        
        let mac_key = if is_server_to_client {
            &encryption_ctx.mac_key_stoc
        } else {
            &encryption_ctx.mac_key_ctos
        };
        
        let mac = encryption_ctx.compute_mac(sequence_number, &encrypted_packet, mac_key)?;
        
        Ok(Self {
            packet_length: packet_length as u32,
            padding_length,
            payload: encrypted_packet,  // 整个packet加密
            padding: vec![0u8; padding_length as usize],  // 已包含在payload中
            mac,
        })
    }
    
    /// 写入加密packet（参考OpenSSH packet.c）
    pub fn write<W: std::io::Write>(&self, stream: &mut W) -> Result<()> {  // 使用泛型（Rust标准）
        // OpenSSH加密packet格式：
        // - packet_length（加密，参考OpenSSH packet.c）
        // - encrypted_packet（padding_length + payload + padding）
        // - MAC
        
        // ⚠️ 简化实现：packet_length不加密（OpenSSH某些配置）
        stream.write_u32::<BigEndian>(self.packet_length)?;
        stream.write_all(&self.payload)?;
        stream.write_all(&self.mac)?;
        
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    
    #[test]
    fn test_aes256_ctr_encryption() {
        let key = vec![0u8; 32];
        let plaintext = b"Hello World";
        
        let mut ctx = EncryptionContext::from_session_keys(&SessionKeys {
            session_id: vec![0u8; 32],
            encryption_key_ctos: key.clone(),
            encryption_key_stoc: key.clone(),
            mac_key_ctos: vec![0u8; 32],
            mac_key_stoc: vec![0u8; 32],
        });
        
        let ciphertext = ctx.encrypt_packet(plaintext, &key).unwrap();
        let decrypted = ctx.decrypt_packet(&ciphertext, &key).unwrap();
        
        assert_eq!(plaintext.to_vec(), decrypted);
    }
    
    #[test]
    fn test_hmac_sha256() {
        let key = vec![0u8; 32];
        let data = b"test data";
        
        let ctx = EncryptionContext::from_session_keys(&SessionKeys {
            session_id: vec![0u8; 32],
            encryption_key_ctos: vec![0u8; 32],
            encryption_key_stoc: vec![0u8; 32],
            mac_key_ctos: key.clone(),
            mac_key_stoc: vec![0u8; 32],
        });
        
        let mac = ctx.compute_mac(1, data, &key).unwrap();
        assert_eq!(mac.len(), 32);  // HMAC-SHA256 = 32字节
        
        // 验证MAC
        assert!(ctx.verify_mac(1, data, &mac, &key).unwrap());
    }
}
