"""
Реализовать класс ConsoleView, который отображает лабиринт,
текущее положение игрока (если реализован пошаговый режим) и найденный путь.
Метод render(maze, player_position, path) рисует карту в консоли."""

import os

from task2.mazeObjects.cell import Cell
from task2.mazeObjects.maze import Maze
from task2.mazeObjects.path import Path
from task2.observerSubject import MazeEvent, MazeEventType, Observer

SBROS = "\033[0m"

WALL = "#"
EXIT = "E"
START = "S"
PATH_SYMBOL = "+"
SPACE_SYMBOL = " "

# Я убрал аргументы из render(), чтобы не передавать их при каждом запуске.
# И работать внутри класса приятнее, чем тянуть эти аргументы туда-сюда 
class ConsoleView(Observer):
    maze:Maze|None
    path:Path|None
    
    def __init__(self, maze:Maze|None=None, path:Path|None=None):
        super().__init__()
        self.maze = maze
        self.path = path

    def _getCellColored(self, cell:Cell) -> str:
        if cell.isWall:
            # Белый
            return self._fmt_str(7, 7, WALL)
        elif cell.isExit:
            # Кислотно-зелёный
            return self._fmt_str(12, 7, EXIT)
        elif cell.isStart:
            # Кислотно-красный
            return self._fmt_str(9, 7, START)
        elif self.path and self.path.array: 
            if cell in self.path.array:
                # Градиент
                percent = self.path.array.index(cell) / len(self.path.array)
                n = self._ANSICalculator(*self._getGradient(percent))
                return self._fmt_str(n, 10, PATH_SYMBOL)
        return SPACE_SYMBOL
        
    def _fmt_str(self, bg:int, fg:int, symbol:str) -> str:
        return f"\033[48;5;{bg}m\033[38;5;{fg}m{symbol}{SBROS}"

    def _ANSICalculator(self, r:int, g:int, b:int):
        r = max(0, min(5, r))
        g = max(0, min(5, g))
        b = max(0, min(5, b))
        return 16 + 36*r + 6*g + b

    def _getGradient(self, percent:float):
        r = 5 * (1-percent)
        g = 0
        b = 5 * percent
        return int(round(r)), int(round(g)), int(round(b))

    def render(self, player_position=None):
        """
        Печатем ячейку.
        Цвет зависит от индекса ячейчки в массиве path.
        Если в массиве нет - просто белый.
        """

        os.system('cls' if os.name == 'nt' else 'clear')

        if not self.maze:
            print("Лабиринт ещё не загружен")
            return None

        output = ""
        for y in range(self.maze.height):
            for x in range(self.maze.width):
                cell = self.maze.getCell(x, y)
                output += self._getCellColored(cell)
            output += "\n"
        print(output) 
    
    def update(self, event: MazeEvent):
        if event.evtype in (MazeEventType.MAZE_LOADED, MazeEventType.PATH_FOUND, MazeEventType.MOVE):
            if event.evtype == MazeEventType.PATH_FOUND:
                if not event.data: raise ValueError
                self.path = event.data
            if event.evtype == MazeEventType.MAZE_LOADED:
                if not event.data: raise ValueError
                self.maze = self.maze
            self.render()
