from abc import ABC, abstractmethod
from typing import Optional
from models import Cell, Maze


class Player:
    
    def __init__(self, start_cell: Cell):
        self.current_cell = start_cell
    
    def move_to(self, new_cell: Cell) -> None:
        self.current_cell = new_cell


class Command(ABC):
    
    @abstractmethod
    def execute(self) -> bool:
        pass
    
    @abstractmethod
    def undo(self) -> None:
        pass


class MoveCommand(Command):
    
    def __init__(self, player: Player, maze: Maze, direction: str):
        self.player = player
        self.maze = maze
        self.direction = direction
        self.previous_cell: Optional[Cell] = None
        self.new_cell: Optional[Cell] = None
    
    def _get_target_cell(self) -> Optional[Cell]:
        x, y = self.player.current_cell.x, self.player.current_cell.y
        
        if self.direction == 'w':
            y -= 1
        elif self.direction == 's':
            y += 1
        elif self.direction == 'a':
            x -= 1
        elif self.direction == 'd':
            x += 1
        else:
            return None
        
        return self.maze.get_cell(x, y)
    
    def execute(self) -> bool:
        self.previous_cell = self.player.current_cell
        self.new_cell = self._get_target_cell()
        
        if self.new_cell and self.new_cell.is_passable():
            self.player.move_to(self.new_cell)
            return True
        return False
    
    def undo(self) -> None:
        if self.previous_cell:
            self.player.move_to(self.previous_cell)