"""
maze_solver/model.py - модель лабиринта (этап 1, без паттернов).
"""

class Cell:
    """Клетка лабиринта.

    Атрибуты:
        x, y           - координаты
        is_wall        - стена ли
        is_start       - стартовая клетка
        is_exit        - клетка выхода
        weight         - стоимость прохода (по умолчанию 1, для взвешенного режима >1)
    """
    __slots__ = ("x", "y", "is_wall", "is_start", "is_exit", "weight")

    def __init__(self, x, y, is_wall=False, is_start=False, is_exit=False, weight=1):
        self.x = x
        self.y = y
        self.is_wall = is_wall
        self.is_start = is_start
        self.is_exit = is_exit
        self.weight = weight

    def is_passable(self):
        return not self.is_wall

    def __repr__(self):
        return f"Cell({self.x},{self.y},wall={self.is_wall})"


class Maze:
    """Лабиринт как двумерный массив клеток.

    Атрибуты:
        width, height   - размеры
        grid            - список списков клеток [y][x]
        start, exit_    - ссылки на клетки старта и выхода (могут быть None при ошибке)
    """

    def __init__(self, width, height):
        self.width = width
        self.height = height
        self.grid = [[Cell(x, y, is_wall=True) for x in range(width)]
                     for y in range(height)]
        self.start = None
        self.exit_ = None

    def get_cell(self, x, y):
        if 0 <= x < self.width and 0 <= y < self.height:
            return self.grid[y][x]
        return None

    def get_neighbors(self, cell):
        """Соседи (вверх, вниз, влево, вправо), только проходимые и в пределах поля."""
        out = []
        for dx, dy in ((0, -1), (0, 1), (-1, 0), (1, 0)):
            nb = self.get_cell(cell.x + dx, cell.y + dy)
            if nb is not None and nb.is_passable():
                out.append(nb)
        return out

    def render_text(self, path=None, player=None):
        """Возвращает текстовое представление лабиринта.

        '#' стена, ' ' проход, 'S' старт, 'E' выход,
        '.' клетка пути, '@' игрок.
        """
        path_set = set()
        if path:
            for c in path:
                path_set.add((c.x, c.y))

        lines = []
        for y in range(self.height):
            row = []
            for x in range(self.width):
                cell = self.grid[y][x]
                ch = ' '
                if cell.is_wall:
                    ch = '#'
                elif cell.is_start:
                    ch = 'S'
                elif cell.is_exit:
                    ch = 'E'
                elif (x, y) in path_set:
                    ch = '.'
                if player is not None and player.x == x and player.y == y:
                    ch = '@'
                row.append(ch)
            lines.append("".join(row))
        return "\n".join(lines)
