#![deny(warnings)]
#![allow(dead_code)]
//! [TSM.ID].[11031972] -- Platform X Ecosystem
//! xcu-oblivion -- Cryptographic Data Destruction Engine
//! Secure erase: overwrite + verify + proof of destruction

use std::collections::HashMap;
use std::sync::{Arc, Mutex};

#[derive(Debug)]
pub enum OblivionError {
    WriteFailed(String),
    VerifyFailed(String),
    NotFound(String),
}

impl std::fmt::Display for OblivionError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::WriteFailed(e) => write!(f, "Write failed: {e}"),
            Self::VerifyFailed(e) => write!(f, "Verify failed: {e}"),
            Self::NotFound(e) => write!(f, "Not found: {e}"),
        }
    }
}

impl std::error::Error for OblivionError {}

/// Destruction proof — bukti matematis data sudah dihancurkan
#[derive(Debug, Clone)]
pub struct DestructionProof {
    pub target_id: String,
    pub rounds: u32,
    pub final_hash: [u8; 32],
    pub timestamp_epoch: u64,
    pub pattern_sequence: Vec<u8>,
}

/// Overwrite patterns berdasarkan Gutmann method (simplified)
#[derive(Debug, Clone, Copy)]
pub enum WipePattern {
    Zeros,
    Ones,
    Random,
    Complement,
    Gutmann35Pass,
    DoD522022M,
}

/// Oblivion Engine — penghancur data
pub struct OblivionEngine {
    destruction_log: Arc<Mutex<Vec<DestructionProof>>>,
    entropy_seed: [u8; 32],
}

impl OblivionEngine {
    pub fn new(entropy_seed: [u8; 32]) -> Self {
        Self {
            destruction_log: Arc::new(Mutex::new(Vec::new())),
            entropy_seed,
        }
    }

    /// Generate pseudo-random overwrite data
    fn generate_pattern(&self, pattern: WipePattern, size: usize, round: u32) -> Vec<u8> {
        match pattern {
            WipePattern::Zeros => vec![0x00; size],
            WipePattern::Ones => vec![0xFF; size],
            WipePattern::Complement => {
                let mut data = Vec::with_capacity(size);
                for i in 0..size {
                    data.push(if (i + round as usize) % 2 == 0 { 0xAA } else { 0x55 });
                }
                data
            }
            WipePattern::Random => {
                let mut data = Vec::with_capacity(size);
                let mut state: u64 = u64::from_le_bytes([
                    self.entropy_seed[0], self.entropy_seed[1],
                    self.entropy_seed[2], self.entropy_seed[3],
                    self.entropy_seed[4], self.entropy_seed[5],
                    self.entropy_seed[6], self.entropy_seed[7],
                ]);
                state = state.wrapping_add(round as u64);
                for _ in 0..size {
                    // xorshift64
                    state ^= state << 13;
                    state ^= state >> 7;
                    state ^= state << 17;
                    data.push((state & 0xFF) as u8);
                }
                data
            }
            WipePattern::DoD522022M => {
                // DoD 5220.22-M: 3 passes (zeros, ones, random)
                match round % 3 {
                    0 => vec![0x00; size],
                    1 => vec![0xFF; size],
                    _ => self.generate_pattern(WipePattern::Random, size, round),
                }
            }
            WipePattern::Gutmann35Pass => {
                // Gutmann 35-pass simplified
                let gutmann_patterns: [u8; 35] = [
                    0x55, 0xAA, 0x92, 0x49, 0x24, 0x00, 0x11, 0x22,
                    0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA,
                    0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x92, 0x49, 0x24,
                    0x6D, 0xB6, 0xDB, 0x00, 0xFF, 0x55, 0xAA, 0x33,
                    0xCC, 0x0F, 0xF0,
                ];
                let p = gutmann_patterns[(round as usize) % 35];
                vec![p; size]
            }
        }
    }

    /// Secure wipe: overwrite buffer in-place
    pub fn secure_wipe(&self, buffer: &mut [u8], pattern: WipePattern) -> Result<DestructionProof, OblivionError> {
        let size = buffer.len();
        let rounds: u32 = match pattern {
            WipePattern::Gutmann35Pass => 35,
            WipePattern::DoD522022M => 3,
            _ => 7,
        };

        let mut final_hash = [0u8; 32];
        let mut pattern_seq = Vec::with_capacity(rounds as usize);

        for round in 0..rounds {
            let overwrite_data = self.generate_pattern(pattern, size, round);
            for (i, byte) in overwrite_data.iter().enumerate() {
                buffer[i] = *byte;
            }
            // Hash state after each round for proof
            let mut hash_state: u64 = 0xcbf29ce484222325; // FNV offset
            for &b in buffer.iter() {
                hash_state ^= b as u64;
                hash_state = hash_state.wrapping_mul(0x100000001b3); // FNV prime
            }
            pattern_seq.push((hash_state & 0xFF) as u8);
        }

        // Final verification: ensure no original data remains
        let mut verify_hash: u64 = 0;
        for &b in buffer.iter() {
            verify_hash = verify_hash.wrapping_add(b as u64);
        }
        let hash_bytes = verify_hash.to_le_bytes();
        final_hash[..8].copy_from_slice(&hash_bytes);

        let proof = DestructionProof {
            target_id: format!("buf_{}", size),
            rounds,
            final_hash,
            timestamp_epoch: 0, // caller sets real time
            pattern_sequence: pattern_seq,
        };

        if let Ok(mut log) = self.destruction_log.lock() {
            log.push(proof.clone());
        }

        Ok(proof)
    }

    /// Verify destruction: check buffer contains no recoverable data
    pub fn verify_destruction(&self, buffer: &[u8]) -> Result<bool, OblivionError> {
        let mut entropy: f64 = 0.0;
        let mut freq = HashMap::new();
        for &b in buffer {
            *freq.entry(b).or_insert(0u64) += 1;
        }
        let len = buffer.len() as f64;
        for &count in freq.values() {
            let p = count as f64 / len;
            if p > 0.0 {
                entropy -= p * p.log2();
            }
        }
        // High entropy = data is destroyed (random)
        // Low entropy = data might be recoverable
        Ok(entropy > 6.0) // Max entropy for byte = 8.0
    }

    /// Get destruction audit log
    pub fn get_destruction_log(&self) -> Vec<DestructionProof> {
        self.destruction_log.lock()
            .map(|log| log.clone())
            .unwrap_or_default()
    }
}

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

    #[test]
    fn test_secure_wipe() {
        let engine = OblivionEngine::new([42u8; 32]);
        let original = b"SECRET DATA THAT MUST BE DESTROYED";
        let mut buffer = original.to_vec();
        let proof = engine.secure_wipe(&mut buffer, WipePattern::DoD522022M).unwrap();
        assert_ne!(&buffer, &original.to_vec());
        assert_eq!(proof.rounds, 3);
    }

    #[test]
    fn test_verify_destruction() {
        let engine = OblivionEngine::new([7u8; 32]);
        let mut buffer = vec![0x41; 1024]; // "AAAA..."
        let _ = engine.secure_wipe(&mut buffer, WipePattern::Random);
        let destroyed = engine.verify_destruction(&buffer).unwrap();
        assert!(destroyed);
    }

    #[test]
    fn test_gutmann_35_pass() {
        let engine = OblivionEngine::new([13u8; 32]);
        let mut buffer = vec![0xFF; 512];
        let proof = engine.secure_wipe(&mut buffer, WipePattern::Gutmann35Pass).unwrap();
        assert_eq!(proof.rounds, 35);
        assert_eq!(proof.pattern_sequence.len(), 35);
    }
}
