use crate::message::Card;
use crate::storage::{StorageProvider, StorageError};

#[derive(Debug)]
pub struct MemoryCard {
    content: String,
    clean_on_eject: bool
}

impl MemoryCard {
    pub fn new() -> Self {
        Self {
            content: String::new(),
            clean_on_eject: true
        }
    }

    #[cfg(test)]
    pub fn new_with_content(content: &str) -> Self {
        Self {
            content: content.to_string(),
            clean_on_eject: false
        }
    }
}

impl StorageProvider for MemoryCard {
    fn using(&mut self, card: Card) -> Result<(), StorageError> {
        match card {
            Card::MemoryCard { text: content } => {
                self.content = content;
                Ok(())
            },
            _ => Err(StorageError::InvalidCard(card))
        }
    }

    fn read(&self) -> Result<String, StorageError> {
        Ok(self.content.clone())
    }

    fn write(&mut self, content: &str) -> Result<(), StorageError> {
        self.content = content.to_string();
        Ok(())
    }

    fn eject(&mut self) {
        if self.clean_on_eject {
            self.content = String::new();
        }
    }
}

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

    #[test]
    pub fn when_a_memory_card_is_read_then_return_its_content() {

        // Arrange
        
        const CONTENT: &str = "This is is card content.";
        let card = MemoryCard::new_with_content(CONTENT);

        // Act
        
        let result = card.read();
        
        // Assert
        
        assert_eq!(Ok(CONTENT.to_string()), result);
    }

    #[test]
    pub fn when_a_memory_card_is_written_then_return_its_content() {
        // Arrange
        const CONTENT: &str = "Updated content.";
        let mut card = MemoryCard::new_with_content("This content should not be found at the end of test.");

        // Act
        let result = card.write(CONTENT);
        
        // Assert
        assert!(result.is_ok(), "Error writing the card");

        match card.read() {
            Ok(text) => assert_eq!(CONTENT.to_string(), text, "Card does not containt the expected text"),
            _ => assert!(false, "Error reading the card")
        }
    }
}
