#!/usr/bin/env python3
"""
Demo script showing how an agent can use dead end marking functionality in MazeWrapper.
This demonstrates the agent's ability to mark positions as dead ends during navigation.
"""

import os
import sys
sys.path.append(os.path.dirname(os.path.abspath(__file__)))

from maze_generation import MazeGenerator
from maze_wrapper import MazeWrapper

def demonstrate_agent_dead_end_marking():
    """Demonstrate how an agent can mark dead ends during navigation."""
    print("Agent Dead End Marking Demo")
    print("=" * 50)
    
    # Create a medium-sized maze
    print("1. Creating a 15x15 maze...")
    generator = MazeGenerator(maze_size=15)
    agent = MazeWrapper(generator)
    
    print(f"   Agent starting at: {agent.get_agent_position()}")
    
    # Create output directory
    output_dir = "agent_dead_end_demo"
    os.makedirs(output_dir, exist_ok=True)
    
    # Save initial state
    initial_file = os.path.join(output_dir, "01_agent_start.png")
    agent.save_maze_with_path_image("01_agent_start.png")
    print(f"   Saved initial state: {initial_file}")
    
    # Agent action: Mark current position as dead end
    print("\n2. Agent Action: Mark current position as dead end")
    mark_success = agent.mark_dead_end()
    print(f"   ✅ Marked current position: {mark_success}")
    
    # Agent action: Try to mark a wall (should fail)
    print("\n3. Agent Action: Try to mark a wall position (should fail)")
    wall_position = (0, 0)  # This should be a wall/frame
    mark_success = agent.mark_dead_end(wall_position)
    print(f"   ❌ Tried to mark wall at {wall_position}: {mark_success}")
    
    # Agent navigation with strategic dead end marking
    print("\n4. Agent Navigation with Dead End Marking Strategy")
    print("   Strategy: Mark positions where agent gets stuck or backtracks")
    
    moves_sequence = ['right', 'right', 'down', 'down', 'left', 'up', 'right', 'down', 'right', 'up']
    marked_during_nav = 0
    
    for i, move in enumerate(moves_sequence):
        print(f"\n   Move {i+1}: Attempting '{move}' from {agent.get_agent_position()}")
        
        # Check if this is a dead end before moving
        possible_moves = agent.get_possible_moves()
        if len(possible_moves) <= 1:  # Dead end or near dead end
            print(f"   🚫 Limited options! Only {len(possible_moves)} possible moves")
            if agent.mark_dead_end():
                marked_during_nav += 1
                print(f"   📍 Agent marked position {agent.get_agent_position()} as dead end")
        
        # Try the move
        success = agent.try_move(move)
        if success:
            print(f"   ✅ Moved to {agent.get_agent_position()}")
        else:
            print(f"   ❌ Move failed - blocked by wall")
            # Agent could mark this as a problematic direction
            print(f"   📍 Agent remembers this blocked direction")
    
    print(f"\n   Navigation summary:")
    print(f"   - Successful moves: {agent.get_move_count()}")
    print(f"   - Failed moves: {agent.get_failed_move_count()}")
    print(f"   - Dead ends marked during navigation: {marked_during_nav}")
    
    # Save state after navigation and marking
    agent.save_maze_with_path_image("02_after_navigation.png")
    print(f"   Saved navigation state")
    
    # Agent action: Strategic marking based on exploration
    print("\n5. Agent Action: Strategic Dead End Marking")
    print("   Agent marks additional positions based on exploration experience")
    
    # Agent could mark positions where it had limited success
    current_pos = agent.get_agent_position()
    
    # Mark some strategic positions based on agent's "learning"
    strategic_positions = [
        (current_pos[0] + 1, current_pos[1]),  # Adjacent positions
        (current_pos[0], current_pos[1] + 1),
    ]
    
    strategic_marked = 0
    for pos in strategic_positions:
        if agent.mark_dead_end(pos):
            strategic_marked += 1
            print(f"   📍 Agent strategically marked {pos}")
    
    print(f"   ✅ Agent marked {strategic_marked} additional strategic positions")
    
    # Save state with strategic markings
    agent.save_maze_with_path_image("03_strategic_markings.png")
    print(f"   Saved state with strategic markings")
    
    # Agent decision making based on marked dead ends
    print("\n6. Agent Decision Making with Dead End Information")
    
    current_pos = agent.get_agent_position()
    print(f"   Current position: {current_pos}")
    print(f"   Is current position marked as dead end: {agent.is_position_marked_dead_end()}")
    
    # Get all marked dead ends for strategic planning
    marked_dead_ends = agent.get_marked_dead_ends()
    print(f"   Total marked dead ends: {len(marked_dead_ends)}")
    
    # Agent strategy: Avoid marked dead ends when possible
    possible_moves = agent.get_possible_moves()
    print(f"   Possible moves: {possible_moves}")
    
    safe_moves = []
    for move in possible_moves:
        # Calculate where this move would take the agent
        direction_map = {'up': (-1, 0), 'down': (1, 0), 'left': (0, -1), 'right': (0, 1)}
        if move in direction_map:
            dr, dc = direction_map[move]
            new_pos = (current_pos[0] + dr, current_pos[1] + dc)
            if new_pos not in marked_dead_ends:
                safe_moves.append(move)
    
    print(f"   Safe moves (avoiding marked dead ends): {safe_moves}")
    
    # Make a strategic move
    if safe_moves:
        strategic_move = safe_moves[0]
        print(f"   🧠 Agent chooses strategic move: '{strategic_move}'")
        success = agent.try_move(strategic_move)
        print(f"   ✅ Strategic move successful: {success}")
    else:
        print(f"   ⚠️  No safe moves available - agent may need to reconsider markings")
    
    # Agent action: Unmark a dead end (agent learns it's not actually problematic)
    print("\n7. Agent Action: Learning and Unmarking")
    
    if marked_dead_ends:
        pos_to_unmark = marked_dead_ends[0]
        print(f"   Agent reconsiders position {pos_to_unmark}")
        unmark_success = agent.unmark_dead_end(pos_to_unmark)
        print(f"   ✅ Agent unmarked position: {unmark_success}")
        print(f"   💡 Agent learned this position might be useful after all")
    
    # Save final state
    agent.save_maze_with_path_image("04_final_agent_state.png")
    
    # Comprehensive analysis
    print("\n8. Final Agent Performance Analysis")
    agent.print_dead_end_analysis()
    
    # Print action summary
    print(f"\n9. Agent Action Summary:")
    print(f"   ✅ Manual marking actions: {agent.get_marking_count()}")
    print(f"   📍 Total positions marked: {len(agent.get_marked_dead_ends())}")
    print(f"   🚶 Movement actions: {agent.get_move_count()}")
    print(f"   ❌ Failed movement attempts: {agent.get_failed_move_count()}")
    print(f"   🎯 Current position: {agent.get_agent_position()}")
    print(f"   🏁 Reached exit: {agent.is_at_exit()}")
    
    print(f"\n   Generated visualizations in '{output_dir}':")
    print(f"   - 01_agent_start.png: Initial agent state")
    print(f"   - 02_after_navigation.png: After navigation with strategic marking")
    print(f"   - 03_strategic_markings.png: After strategic position marking")
    print(f"   - 04_final_agent_state.png: Final agent state with all actions")
    
    return agent

def demonstrate_multiple_agents():
    """Demonstrate how multiple agents could mark dead ends differently."""
    print("\n" + "=" * 60)
    print("MULTIPLE AGENT COMPARISON DEMO")
    print("=" * 60)
    
    # Create the same maze for comparison
    generator = MazeGenerator(maze_size=12)
    
    # Agent 1: Conservative (marks many positions as potential dead ends)
    print("\n1. Conservative Agent (marks frequently)")
    conservative_agent = MazeWrapper(generator)
    
    # Make some moves and mark aggressively
    moves = ['right', 'down', 'right', 'up', 'left']
    for move in moves:
        if conservative_agent.try_move(move):
            # Mark every position visited as potentially problematic
            conservative_agent.mark_dead_end()
    
    conservative_agent.save_maze_with_path_image("05_conservative_agent.png")
    print(f"   Conservative agent marked {len(conservative_agent.get_marked_dead_ends())} positions")
    
    # Agent 2: Strategic (only marks when stuck)
    print("\n2. Strategic Agent (marks selectively)")
    strategic_agent = MazeWrapper(generator)
    
    for move in moves:
        if strategic_agent.try_move(move):
            # Only mark if few options available
            if len(strategic_agent.get_possible_moves()) <= 1:
                strategic_agent.mark_dead_end()
    
    strategic_agent.save_maze_with_path_image("06_strategic_agent.png")
    print(f"   Strategic agent marked {len(strategic_agent.get_marked_dead_ends())} positions")
    
    # Agent 3: Learning agent (marks then unmarks based on experience)
    print("\n3. Learning Agent (marks and corrects)")
    learning_agent = MazeWrapper(generator)
    
    # Initial exploration with marking
    for move in moves[:3]:
        if learning_agent.try_move(move):
            learning_agent.mark_dead_end()  # Mark initially
    
    # Then unmark some based on "experience"
    marked_positions = learning_agent.get_marked_dead_ends()
    if marked_positions:
        learning_agent.unmark_dead_end(marked_positions[0])  # Unmark one
    
    learning_agent.save_maze_with_path_image("07_learning_agent.png")
    print(f"   Learning agent marked {len(learning_agent.get_marked_dead_ends())} positions (after corrections)")
    
    # Comparison
    print(f"\n4. Agent Comparison:")
    print(f"   Conservative: {len(conservative_agent.get_marked_dead_ends())} marked, {conservative_agent.get_marking_count()} actions")
    print(f"   Strategic:    {len(strategic_agent.get_marked_dead_ends())} marked, {strategic_agent.get_marking_count()} actions")
    print(f"   Learning:     {len(learning_agent.get_marked_dead_ends())} marked, {learning_agent.get_marking_count()} actions")

if __name__ == "__main__":
    # Run the main demo
    agent = demonstrate_agent_dead_end_marking()
    
    # Run the multiple agents demo
    demonstrate_multiple_agents()
    
    print("\n" + "=" * 60)
    print("DEMO COMPLETE!")
    print("=" * 60)
    print("Key capabilities demonstrated:")
    print("✅ Agent can mark current position as dead end")
    print("✅ Agent can mark specific positions as dead ends")
    print("✅ Agent can mark positions strategically based on experience")
    print("✅ Agent can unmark positions (learning/correction)")
    print("✅ Agent can use dead end information for strategic decisions")
    print("✅ Agent can avoid marked dead ends when planning moves")
    print("✅ Multiple agents can have different marking strategies")
    print("✅ All actions are visualized with color coding and statistics")
    print("✅ No automatic detection - purely agent-driven marking")
    print("=" * 60) 