"""
maze_solver/command.py - паттерн Command.

Player хранит текущую клетку. MoveCommand двигает игрока в выбранном
направлении и помнит предыдущую позицию для undo. Менеджер CommandHistory
держит стек выполненных команд.
"""

from abc import ABC, abstractmethod


class Player:
    """Игрок в лабиринте."""

    def __init__(self, cell):
        self.cell = cell

    @property
    def x(self): return self.cell.x

    @property
    def y(self): return self.cell.y


class Command(ABC):
    @abstractmethod
    def execute(self): ...
    @abstractmethod
    def undo(self): ...


class MoveCommand(Command):
    """Команда перемещения игрока на одну клетку.

    direction: одна из 'W','A','S','D' (вверх, влево, вниз, вправо).
    """

    DELTAS = {
        'W': (0, -1),
        'S': (0, 1),
        'A': (-1, 0),
        'D': (1, 0),
    }

    def __init__(self, maze, player, direction):
        self.maze = maze
        self.player = player
        self.direction = direction.upper()
        self._prev_cell = None
        self._executed = False

    def execute(self):
        if self.direction not in self.DELTAS:
            return False
        dx, dy = self.DELTAS[self.direction]
        target = self.maze.get_cell(self.player.x + dx, self.player.y + dy)
        if target is None or not target.is_passable():
            return False
        self._prev_cell = self.player.cell
        self.player.cell = target
        self._executed = True
        return True

    def undo(self):
        if not self._executed:
            return False
        self.player.cell = self._prev_cell
        self._executed = False
        return True


class CommandHistory:
    """Стек выполненных команд (для общего undo)."""

    def __init__(self):
        self._stack = []

    def do(self, cmd):
        if cmd.execute():
            self._stack.append(cmd)
            return True
        return False

    def undo(self):
        if not self._stack:
            return False
        return self._stack.pop().undo()
