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


class MazeBuilder(ABC):
    
    @abstractmethod
    def build_from_file(self, filename: str) -> Maze:
        pass


class TextFileMazeBuilder(MazeBuilder):
    
    WALL_CHAR = '#'
    START_CHAR = 'S'
    EXIT_CHAR = 'E'
    PASS_CHAR = ' '
    
    def build_from_file(self, filename: str) -> Maze:
        with open(filename, 'r', encoding='utf-8') as f:
            lines = [line.rstrip('\n') for line in f.readlines()]
        
        if not lines:
            raise ValueError("Файл с лабиринтом пуст")
        
        height = len(lines)
        width = max(len(line) for line in lines)
        
        maze = Maze(width, height)
        
        for y, line in enumerate(lines):
            for x, ch in enumerate(line):
                if x >= width:
                    continue
                
                cell = Cell(x, y)
                
                if ch == self.WALL_CHAR:
                    cell.is_wall = True
                elif ch == self.START_CHAR:
                    cell.is_start = True
                elif ch == self.EXIT_CHAR:
                    cell.is_exit = True
                elif ch == self.PASS_CHAR:
                    pass
                else:
                    cell.is_wall = True
                
                maze.set_cell(x, y, cell)
        
        if maze.start is None:
            raise ValueError("В лабиринте нет стартовой клетки (S)")
        if maze.exit is None:
            raise ValueError("В лабиринте нет выхода (E)")
        
        return maze