use std::collections::HashMap;
use std::io::{self, Write};
use std::thread;
use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
#[derive(Clone, Debug)]
struct Position {
    x: f32,
    y: f32,
}
impl Position {
    fn new(x: f32, y: f32) -> Self {
        Self { x, y }
    }
    
    fn distance_to(&self, other: &Position) -> f32 {
        let dx = self.x - other.x;
        let dy = self.y - other.y;
        (dx * dx + dy * dy).sqrt()
    }
}
#[derive(Debug, PartialEq)]
enum EntityType {
    Player,
    NPC,
}
#[derive(Debug)]
struct Entity {
    id: String,
    name: String,
    entity_type: EntityType,
    position: Position,
    properties: HashMap<String, String>,
}
impl Entity {
    fn new(id: &str, name: &str, entity_type: EntityType, x: f32, y: f32) -> Self {
        Self {
            id: id.to_string(),
            name: name.to_string(),
            entity_type,
            position: Position::new(x, y),
            properties: HashMap::new(),
        }
    }
    
    fn set_property(&mut self, key: &str, value: &str) {
        self.properties.insert(key.to_string(), value.to_string());
    }
    
    fn get_property(&self, key: &str) -> Option<&String> {
        self.properties.get(key)
    }
}
#[derive(Debug)]
struct Memory {
    short_term: Vec<String>,
    long_term: HashMap<String, String>,
    last_interaction: Option<Instant>,
}
impl Memory {
    fn new() -> Self {
        Self {
            short_term: Vec::new(),
            long_term: HashMap::new(),
            last_interaction: None,
        }
    }
    
    fn add_short_term(&mut self, memory: &str) {
        self.short_term.push(memory.to_string());
        
                if self.short_term.len() > 10 {
            self.short_term.remove(0);
        }
        
        self.last_interaction = Some(Instant::now());
    }
    
    fn set_long_term(&mut self, key: &str, value: &str) {
        self.long_term.insert(key.to_string(), value.to_string());
    }
    
    fn get_long_term(&self, key: &str) -> Option<&String> {
        self.long_term.get(key)
    }
}
#[derive(Debug)]
struct NPCAgent {
    entity: Entity,
    role: String,
    memory: Memory,
    dialogue_responses: Vec<String>,
    greeting_responses: Vec<String>,
    last_greeting: Option<Instant>,
}
impl NPCAgent {
    fn new(entity: Entity, role: &str) -> Self {
        Self {
            entity,
            role: role.to_string(),
            memory: Memory::new(),
            dialogue_responses: Vec::new(),
            greeting_responses: Vec::new(),
            last_greeting: None,
        }
    }
    
    fn add_dialogue_response(&mut self, response: &str) {
        self.dialogue_responses.push(response.to_string());
    }
    
    fn add_greeting(&mut self, greeting: &str) {
        self.greeting_responses.push(greeting.to_string());
    }
    
    fn process_player_proximity(&mut self, player_pos: &Position) -> Option<String> {
        let distance = self.entity.position.distance_to(player_pos);
        
                if distance < 3.0 {
            let greeting_cooldown = Duration::from_secs(60);
            
            if self.last_greeting.is_none() || 
               self.last_greeting.unwrap().elapsed() > greeting_cooldown {
                
                                if !self.greeting_responses.is_empty() {
                                        let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
                    let idx = (now.as_millis() % self.greeting_responses.len() as u128) as usize;
                    let greeting = &self.greeting_responses[idx];
                    
                                        self.memory.add_short_term(&format!("I greeted player at distance {:.1}", distance));
                    self.last_greeting = Some(Instant::now());
                    
                    return Some(greeting.clone());
                }
            }
        }
        
        None
    }
    
    fn process_dialogue(&mut self, text: &str) -> String {
                self.memory.add_short_term(&format!("Player said: {}", text));
        
                let text_lower = text.to_lowercase();
        
        if text_lower.contains("name") {
            return format!("My name is {}. I am a {}.", self.entity.name, self.role);
        }
        
        if text_lower.contains("help") {
            return "You can talk to me about various topics. Try asking about my role or the village.".to_string();
        }
        
                if !self.dialogue_responses.is_empty() {
            let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
            let idx = (now.as_millis() % self.dialogue_responses.len() as u128) as usize;
            return self.dialogue_responses[idx].clone();
        }
        
        "Hmm, interesting.".to_string()
    }
}
struct GameWorld {
    player: Entity,
    npcs: Vec<NPCAgent>,
    messages: Vec<String>,
    game_time: f32,
    last_update: Instant,
}
impl GameWorld {
    fn new() -> Self {
        println!("Initializing RPG Demo world...");
        
                let player = Entity::new("player", "Player", EntityType::Player, 0.0, 0.0);
        
                let mut npcs = Vec::new();
        
                let mut merchant = Entity::new("merchant", "Marcus", EntityType::NPC, 5.0, 3.0);
        merchant.set_property("occupation", "Shopkeeper");
        
        let mut merchant_agent = NPCAgent::new(merchant, "Merchant");
        merchant_agent.add_greeting("Welcome to my shop, traveler!");
        merchant_agent.add_greeting("Ah, a customer! Looking to buy or sell?");
        merchant_agent.add_dialogue_response("I have many fine wares. Take a look around.");
        merchant_agent.add_dialogue_response("That'll be 50 gold coins. A fair price, I assure you.");
        merchant_agent.add_dialogue_response("I import goods from all over the realm.");
        merchant_agent.add_dialogue_response("Business has been good lately, despite the troubles to the north.");
        merchant_agent.add_dialogue_response("I might be able to offer a discount for a fellow traveler.");
        npcs.push(merchant_agent);
        
                let mut guard = Entity::new("guard", "Gareth", EntityType::NPC, -5.0, -2.0);
        guard.set_property("occupation", "Village Guard");
        
        let mut guard_agent = NPCAgent::new(guard, "Guard");
        guard_agent.add_greeting("Halt! State your business, traveler.");
        guard_agent.add_greeting("Keep your weapons sheathed while in town.");
        guard_agent.add_dialogue_response("I'm watching you. Don't cause any trouble in my village.");
        guard_agent.add_dialogue_response("There have been reports of bandits on the north road.");
        guard_agent.add_dialogue_response("I've been a guard here for fifteen years.");
        guard_agent.add_dialogue_response("Our laws are simple: no stealing, no fighting, respect others.");
        guard_agent.add_dialogue_response("The captain increased our patrols after the recent dragon sighting.");
        npcs.push(guard_agent);
        
                let mut villager = Entity::new("villager", "Velma", EntityType::NPC, 2.0, -4.0);
        villager.set_property("occupation", "Farmhand");
        
        let mut villager_agent = NPCAgent::new(villager, "Villager");
        villager_agent.add_greeting("Hello there! Nice day, isn't it?");
        villager_agent.add_greeting("Oh! I didn't see you there.");
        villager_agent.add_dialogue_response("Did you hear about the old ruins to the east? They say it's haunted.");
        villager_agent.add_dialogue_response("The harvest festival is next week. You should stay for it!");
        villager_agent.add_dialogue_response("I've lived in this village my whole life.");
        villager_agent.add_dialogue_response("The blacksmith's daughter is sweet on the baker's son. Quite the scandal!");
        villager_agent.add_dialogue_response("We've had strange weather lately. Some say it's magic from the mountains.");
        npcs.push(villager_agent);
        
        println!("Created {} NPCs", npcs.len());
        
        Self {
            player,
            npcs,
            messages: Vec::new(),
            game_time: 0.0,
            last_update: Instant::now(),
        }
    }
    
    fn update(&mut self) {
                let now = Instant::now();
        let delta_time = now.duration_since(self.last_update).as_secs_f32();
        self.last_update = now;
        
                self.game_time += delta_time;
        
                        let mut greetings = Vec::new();
        
        for npc in &mut self.npcs {
            if let Some(greeting) = npc.process_player_proximity(&self.player.position) {
                greetings.push((npc.entity.name.clone(), greeting));
            }
        }
        
                for (name, greeting) in greetings {
            self.add_message(&format!("{}: {}", name, greeting));
        }
    }
    
    fn move_player(&mut self, dx: f32, dy: f32) {
        self.player.position.x += dx;
        self.player.position.y += dy;
        
        println!("Player moved to ({:.1}, {:.1})", self.player.position.x, self.player.position.y);
    }
    
    fn process_chat(&mut self, text: &str) {
                self.add_message(&format!("Player: {}", text));
        
                let mut closest_npc_index = 0;
        let mut closest_distance = f32::MAX;
        
        for (i, npc) in self.npcs.iter().enumerate() {
            let distance = npc.entity.position.distance_to(&self.player.position);
            
            if distance < closest_distance {
                closest_distance = distance;
                closest_npc_index = i;
            }
        }
        
                if closest_distance <= 5.0 {
                        let response;
            let name;
            
            {
                let npc = &mut self.npcs[closest_npc_index];
                response = npc.process_dialogue(text);
                name = npc.entity.name.clone();
            }
            
                        self.add_message(&format!("{}: {}", name, response));
        } else {
            self.add_message("No one is close enough to hear you...");
        }
    }
    
    fn add_message(&mut self, message: &str) {
        println!("{}", message);
        self.messages.push(message.to_string());
        
                if self.messages.len() > 100 {
            self.messages.remove(0);
        }
    }
    
    fn render(&self) {
                print!("\x1B[2J\x1B[1;1H");
        
                println!("=== Oxyde RPG Demo ===");
        println!("Game time: {:.1}s", self.game_time);
        println!();
        
                println!("Player position: ({:.1}, {:.1})", self.player.position.x, self.player.position.y);
        
                println!("\nNPCs:");
        for npc in &self.npcs {
            let distance = npc.entity.position.distance_to(&self.player.position);
            
            println!("- {} ({}) at ({:.1}, {:.1}) - {:.1} units away", 
                npc.entity.name, npc.role, npc.entity.position.x, npc.entity.position.y, distance);
        }
        
                println!("\nRecent messages:");
        let start_idx = if self.messages.len() > 5 { self.messages.len() - 5 } else { 0 };
        for i in start_idx..self.messages.len() {
            println!("  {}", self.messages[i]);
        }
        
                println!("\nControls:");
        println!("WASD: Move player");
        println!("T: Talk to nearest NPC");
        println!("Q: Quit");
        println!("\nPress Enter after typing a command.");
    }
}
fn main() {
        let mut world = GameWorld::new();
    
        loop {
                world.update();
        
                world.render();
        
                let mut input = String::new();
        io::stdout().flush().unwrap();
        io::stdin().read_line(&mut input).unwrap_or(0);
        let input = input.trim().to_lowercase();
        
        if !input.is_empty() {
            match input.as_str() {
                "w" => world.move_player(0.0, 1.0),
                "a" => world.move_player(-1.0, 0.0),
                "s" => world.move_player(0.0, -1.0),
                "d" => world.move_player(1.0, 0.0),
                "q" => break,
                "t" => {
                                        println!("Enter your message:");
                    let mut chat = String::new();
                    io::stdout().flush().unwrap();
                    io::stdin().read_line(&mut chat).unwrap_or(0);
                    world.process_chat(chat.trim());
                },
                _ => {
                    println!("Unknown command: {}", input);
                }
            }
        }
        
                thread::sleep(Duration::from_millis(50));
    }
    
    println!("Thanks for playing the Oxyde RPG Demo!");
}