terrr 0.1.1

a linux horror game
use std::collections::HashMap;

use crate::game::fs::VirtualFileSystem;
use crate::game::state::{GameTime, TerminalState};
use crate::game::commands::Commands;

/// Enum representing terminal command results
pub enum CommandResult {
    /// Success with optional message
    Success(String),
    /// Error with message
    Error(String),
    /// Special event triggered by the command
    Event(String),
    /// No output
    Empty,
}

impl CommandResult {
    pub fn to_string(&self) -> String {
        match self {
            CommandResult::Success(msg) => msg.clone(),
            CommandResult::Error(msg) => format!("Error: {}", msg),
            CommandResult::Event(msg) => msg.clone(),
            CommandResult::Empty => String::new(),
        }
    }
}

/// Function type for command handlers
type CommandHandlerFn = fn(&mut TerminalState, &mut VirtualFileSystem, &GameTime, &[&str]) -> CommandResult;

/// Terminal command handler
pub struct TerminalController {
    pub filesystem: VirtualFileSystem,
    command_handlers: HashMap<String, CommandHandlerFn>,
    pub win_conditions: crate::game::state::WinConditions,
}

impl TerminalController {
    pub fn new() -> Self {
        let mut command_handlers = HashMap::<String, CommandHandlerFn>::new();
        
        // Register command handlers from the Commands module
        command_handlers.insert("help".to_string(), Commands::cmd_help);
        command_handlers.insert("ls".to_string(), Commands::cmd_ls);
        command_handlers.insert("cd".to_string(), Commands::cmd_cd);
        command_handlers.insert("cat".to_string(), Commands::cmd_cat);
        command_handlers.insert("pwd".to_string(), Commands::cmd_pwd);
        command_handlers.insert("echo".to_string(), Commands::cmd_echo);
        command_handlers.insert("grep".to_string(), Commands::cmd_grep);
        command_handlers.insert("touch".to_string(), Commands::cmd_touch);
        command_handlers.insert("mkdir".to_string(), Commands::cmd_mkdir);
        command_handlers.insert("rm".to_string(), Commands::cmd_rm);
        command_handlers.insert("clear".to_string(), Commands::cmd_clear);
        command_handlers.insert("time".to_string(), Commands::cmd_time);
        command_handlers.insert("whoami".to_string(), Commands::cmd_whoami);
        command_handlers.insert("man".to_string(), Commands::cmd_man);
        command_handlers.insert("flags".to_string(), Commands::cmd_flags);
        command_handlers.insert("submit".to_string(), Commands::cmd_submit);
        command_handlers.insert("watcher".to_string(), Commands::cmd_watcher);
        
        Self {
            filesystem: VirtualFileSystem::new(),
            command_handlers,
            win_conditions: crate::game::state::WinConditions::default(),
        }
    }
    
    /// Process a command and return the result
    pub fn process_command(
        &mut self, 
        terminal: &mut TerminalState, 
        game_time: &GameTime, 
        command: &str,
        win_conditions: &mut crate::game::state::WinConditions
    ) -> CommandResult {
        if command.trim().is_empty() {
            return CommandResult::Empty;
        }
        
        // Add command to history
        terminal.command_history.push(command.to_string());
        
        // Special case: Check if someone is writing the special phrase to the diary
        if command.starts_with("echo") && command.contains("i see you for who you are") {
            let diary_path = "/home/user/personal/diary.txt";
            if self.filesystem.get_file(diary_path).is_some() {
                // When the phrase is echoed, mark the hidden flag as discoverable
                // We'll check for this when cat command is used on the diary
                if let Some(idx) = win_conditions.flags.iter().position(|f| f.name == "HIDDEN_TRUTH") {
                    win_conditions.flags[idx].found = true;
                }
            }
        }
        
        // Split command into parts
        let parts: Vec<&str> = command.split_whitespace().collect();
        if parts.is_empty() {
            return CommandResult::Empty;
        }
        
        let cmd_name = parts[0].to_lowercase();
        let args = &parts[1..];
        
        // Check for secret commands first (like summon and forbidden)
        if let Some(result) = Commands::handle_secret_command(
            terminal, 
            &mut self.filesystem, 
            game_time, 
            &cmd_name, 
            args, 
            win_conditions
        ) {
            return result;
        }
        
        // Check for midnight or 3 AM effects
        let mut corrupted_command = false;
        if game_time.is_midnight() || game_time.is_three_am() {
            // 20% chance of command corruption at midnight/3AM
            if rand::random::<f32>() < 0.2 {
                corrupted_command = true;
            }
        }
        
        // Special handling for cat command with diary
        if cmd_name == "cat" && !args.is_empty() {
            let target = args[0];
            let target_path = self.filesystem.resolve_path(&terminal.current_dir, target);
            
            // Check if we're looking at the diary file and the hidden flag is found
            if target_path == "/home/user/personal/diary.txt" {
                let hidden_flag_found = win_conditions.flags
                    .iter().any(|f| f.name == "HIDDEN_TRUTH" && f.found);
                
                if hidden_flag_found {
                    if let Some(file) = self.filesystem.get_file(&target_path) {
                        let mut content = file.content.clone();
                        content.push_str("\n\n---------- HIDDEN MESSAGE REVEALED ----------\n");
                        content.push_str("You have found the HIDDEN_TRUTH flag!\n");
                        content.push_str("This reveals the full middle part of the command: 'shouldhavelistened'\n");
                        content.push_str("The entity has been watching you all along.\n");
                        content.push_str("--------------------------------------------\n");
                        return CommandResult::Success(content);
                    }
                }
            }
        }

        // Process the command
        let result = if corrupted_command {
            self.handle_corrupted_command(&cmd_name, args, game_time)
        } else if let Some(handler) = self.command_handlers.get(&cmd_name) {
            handler(terminal, &mut self.filesystem, game_time, args)
        } else {
            CommandResult::Error(format!("Command not found: {}", cmd_name))
        };
        
        result
    }
    
    /// Handle corrupted commands (when at midnight or 3AM)
    fn handle_corrupted_command(&self, cmd: &str, _args: &[&str], game_time: &GameTime) -> CommandResult {
        if game_time.is_three_am() {
            let messages = [
                "I̴ ̶s̴e̵e̷ ̸y̷o̴u̷",
                "I̷̞̹̭̞̮̫̜̘̽̏͒̾̒̋̕͝t̵̡͕̝̪͕̓̆̾̔͗̾'̷̧͉̳̟̄s̵̻̠̬̈̒̌̉͆ ̸̗̠͔̭̬̤̌̔̈̚͠a̸̰̹̖̤̎̃͒ͅl̶̡̗̘͈̖̓͆̾̌w̴̻̞̠̗̟̌͂a̴̻̗̣̝̼̋ý̵̫̜͚̍s̴̡̳̫̠̆̾͛̎̋̄͝ ̴̠̣̑̒̎̒͊̃͠w̸̳̖̼̉͆̌̈͘̚͝ǎ̷̲͍̔͑̂ͅt̶̢̬͚͙̖͇͉̃́̆͗̈́c̷̹̬͊̃̏̌̔h̴̹̙͙̜̮̑͜͝͠i̸̢̝̗̱̦̼̝̗̒̂n̷̩̰̱̫̭̖̖̮̑̋̈́͆̇̈́͝g̵̬̼̋̋̿̏̕̚̚ͅ",
                "D̷̗̦̱̱̯̍͆̎̀̀̒̑͜͠ơ̸̡̧̰̺̱͔̙̩̒̏̈̇͝ ̶̯̯͚̳͈̮̉͗̑͒n̶͚̤̞̽͜ö̴̠̯̯̩̲̹̹́̂́́̋̓͘t̸̮̦̭͗̓̎̏̀ ̶̢̜̝̙̐̃̈́́̉̏̍͝t̴̤̪̏̓͛͐͛̚͝r̵̠̗̋͆̈̈́ų̵̰̤͉̯͕͈̄̋s̵̢̮̦͑̌̒̈̏̿̏̚ͅt̵̩̞͓͚̫̝͊̿̓̍͘͜ ̴̜̙͚͐͛͗̓t̵̛̘̬̞̩͓͕̳̹̐̇h̵̟̀͑̅̾͊̽̚͘e̵̤̤̝̟̟̲̙̒̃ ̶̖̻͈̺͌̓t̵̢̳̯͙̝̽ẹ̴̓̕r̶̢͈̳̝̰̣͆͘ͅṃ̴̦̺̠͖͒i̶̢̻̮̱͇̮̎͐̿̽̈́̄ͅņ̵̤͓͑̒͋͛͝ȧ̶̛͔̰̯͖̳͖̋͌̈́l̸̢̯͊̅̕",
                "I̵̱̩͒̐ẗ̶̢̻̹̹́'̶̗̉s̸͚̬̪̄ ̴̖̀͘͘3̸̧̗̑̈:̵̧̬̌0̸̨̛̜̠͊̈́0̶̪̥̻̒ ̷͉̹̆a̵̭͔̬͆̇͊m̴͓̫̀̿.̴̨͚̙̽ ̵͓̣̆́D̵̫̭͒̅͜o̷̲̦̒̇ ̸̯̈́̄ÿ̶̩́o̶̧̧͘u̶̬̖͛̏͜ ̷͎̬̽̆͘k̵̮̜̥͐̏͊n̴̡̘̥̅ọ̸̢̥̈́̾͝w̵̨̢̢͐ ̶̗͈̗̽̃w̸̧̟̣͑̿̍h̶̞̫͕̋̓̎ä̸̼͖͕̍͝t̶͉̦̂ ̶̻͊w̶̯͖̭̽a̶̩͓̠̿t̴̡̯̀͂c̵̨̠̼̔͊ḧ̴̺́̓e̵̘̊̌s̴̨̗̙̀̔ ̸̬̤͗̆̐ŷ̶̗̱o̶̬̔u̸̹̬̇̑ ̷̥̠̍̑͋i̶̪̖̓̃n̴̬̗̲̈́̕͝ ̸̧̼̼͂ẗ̴͓͙́̽h̶̩̠͓͋͘e̵̡̦̠̐̔ ̵̢̮͇̄̌d̵̼̈́̒a̵̩͎̙̍̍̀r̴̪̞͙̽̎k̵̻̉̃?̸̗͍̓̎̈",
                "S̷̪̣͓̩͉̬̩̪̳͎̫̟͛̈̀͑̂̾͘̚͜͝h̶̬̗͉̰̿̋̐͐͂̿̿̎̏̐͊͝e̴͍̫̼̺̜̋͛͒͂͊ ̷̧̯͎͔̤̜͚̈́̂̒̄̊̕͜w̶̡̠̝͚̭̻̣̞͕̫̽͂̅͒̏̐͐̽̾̈́̓̑́̔ḁ̸̱̦̖͈̦̜̥̱̬͔̔̓̂̍͜͜ͅṡ̸͔͂̋̔̅͝ ̸̻̠͙̀̒̃̀͝͝ǹ̴̨̢̡̪̹̦̹̤̹͉͓̣̦̍̓͆̈́̽͂̍̆̒̅͜͠ͅè̵̞̬͇̥̗̫̙̣̥̎̏̌̊́͑v̶̭͙̩̻̙͍̟̳̲͙̣̖̏̿̐̃̌̈̿̓̕̕͝e̸̡̫͎̬̤̙̮͔̱̱̦͓͑̋͜r̵̡̼̯̳͊̾̆̓̍͋̑̒̌͜ ̴̮̮̼̞̰̈̒̈́̓̏̐̿͌̊̿̆̓͠ͅd̵̦͒̿̄̆̌̽̎̒̋̚͝ę̸̮̜̫̲͈̰̜̲͍̍͂̊̊̅͐͑̈́̊̂͠â̵̫̥̗͕̘̘̗̽͜ͅḑ̶̢̯͓̖̎͋̎̓́"
            ];
            
            CommandResult::Event(messages[rand::random::<usize>() % messages.len()].to_string())
        } else if game_time.is_midnight() {
            let messages = [
                "It's midnight. They're here.",
                "The terminal seems to be watching you.",
                "You hear something moving in the system.",
                "The command failed in an unexpected way.",
                "The lights in the room seem to dim for a moment."
            ];
            
            // 50% chance to execute original command, 50% chance for creepy message
            if rand::random::<bool>() {
                CommandResult::Error(messages[rand::random::<usize>() % messages.len()].to_string())
            } else {
                // Let it execute the real command with a glitchy warning
                CommandResult::Error(format!("Warning: {} processed with unexpected side effects", cmd))
            }
        } else {
            CommandResult::Error(format!("Command failed: {}", cmd))
        }
    }
    
}