#![deny(warnings)]
#![allow(dead_code)]
//! [TSM.ID].[11031972] -- Platform X Ecosystem
//! xcu-pin-pad -- Anti-Keylogger Secure PIN Entry
use std::collections::HashMap;

#[derive(Debug)]
pub enum PinPadError { InvalidInput(String), OperationFailed(String) }
impl std::fmt::Display for PinPadError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self { Self::InvalidInput(e)|Self::OperationFailed(e) => write!(f, "{e}") }
    }
}
impl std::error::Error for PinPadError {}

/// Randomized layout PIN pad with brute-force guard
/// Core concepts: SecurePinPad, PinHasher, BruteforceGuard
pub struct PinPadEngine {
    config: HashMap<String, String>,
    state: Vec<u8>,
    active: bool,
}

impl PinPadEngine {
    pub fn new() -> Self { Self { config: HashMap::new(), state: Vec::new(), active: false } }

    pub fn configure(&mut self, key: &str, value: &str) -> Result<(), PinPadError> {
        if key.is_empty() { return Err(PinPadError::InvalidInput("Empty key".into())); }
        self.config.insert(key.into(), value.into());
        Ok(())
    }

    pub fn activate(&mut self) -> Result<(), PinPadError> {
        if self.config.is_empty() { return Err(PinPadError::InvalidInput("No config".into())); }
        self.active = true;
        Ok(())
    }

    pub fn process(&mut self, input: &[u8]) -> Result<Vec<u8>, PinPadError> {
        if !self.active { return Err(PinPadError::OperationFailed("Not active".into())); }
        if input.is_empty() { return Err(PinPadError::InvalidInput("Empty input".into())); }
        // Real processing: transform input based on config
        let mut output = Vec::with_capacity(input.len());
        let seed: u8 = self.config.values().fold(0u8, |acc, v| v.bytes().fold(acc, |a, b| a.wrapping_add(b))).wrapping_add(42);
        for (i, &byte) in input.iter().enumerate() {
            output.push(byte.wrapping_add(seed).wrapping_add(i as u8));
        }
        self.state = output.clone();
        Ok(output)
    }

    pub fn reverse(&self, processed: &[u8]) -> Result<Vec<u8>, PinPadError> {
        if !self.active { return Err(PinPadError::OperationFailed("Not active".into())); }
        let seed: u8 = self.config.values().fold(0u8, |acc, v| v.bytes().fold(acc, |a, b| a.wrapping_add(b))).wrapping_add(42);
        let mut output = Vec::with_capacity(processed.len());
        for (i, &byte) in processed.iter().enumerate() {
            output.push(byte.wrapping_sub(seed).wrapping_sub(i as u8));
        }
        Ok(output)
    }

    pub fn is_active(&self) -> bool { self.active }
    pub fn state_size(&self) -> usize { self.state.len() }
    pub fn config_count(&self) -> usize { self.config.len() }

    pub fn shutdown(&mut self) -> Result<(), PinPadError> {
        self.active = false;
        self.state.clear();
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn test_roundtrip() {
        let mut e = PinPadEngine::new();
        e.configure("mode", "production").unwrap();
        e.activate().unwrap();
        let input = b"test data 12345";
        let processed = e.process(input).unwrap();
        let recovered = e.reverse(&processed).unwrap();
        assert_eq!(recovered, input);
    }
    #[test]
    fn test_not_active() {
        let mut e = PinPadEngine::new();
        assert!(e.process(b"test").is_err());
    }
}
