import time as _tm
import sys as _ss
import subprocess as _sb
import random as _rn

class Timer:
    """
        Create timer

        Example:
            import time

            timer = Timer()
            timer.start()
            time.sleep(5.11)
            timer.end()

            print(timer.get())"""
    def __init__(self, decimals:int=2):
        """
        Create timer

        Example:
            import time

            timer = Timer()
            timer.start()
            time.sleep(5.11)
            timer.end()

            print(timer.get())"""
        self.starttime = 0.0
        self.endtime = 0.0
        self.decimals = decimals
    
    def start(self):
        """Start timer"""
        self.starttime = _tm.time()
    
    def end(self):
        """Stop timer"""
        self.endtime = _tm.time() - self.starttime
    
    def get(self):
        """Get the time timer value"""
        return round(self.endtime, self.decimals)

    def reset(self):
        """Reset timer"""
        self.endtime = 0.0
        self.starttime = 0.0

class logging:
    """Record all actions."""
    def __init__(self, *, time:bool=True, lighting:bool=False, timestyle:str="%H:%M:%S"):
        """Record all actions."""
        self.log = []
        self.time = time
        self.lighting = lighting
        self.timestyle = timestyle

    def AddAction(self, text:str, state:int = 1):
        """States:
            1 - Info;
            2 - Waring;
            3 - Error;
            other - Unknow;"""
        if self.time:current_time = f"({_tm.strftime(self.timestyle, _tm.localtime())})"
        else:current_time = ""
        if state == 1:
            status = "INFO"
            if self.lighting:color = "\033[34m"
            else:color = ""
        elif state == 2:
            status = "WARING"
            if self.lighting:color = "\033[33m"
            else:color = ""
        elif state == 3:
            status = "ERROR"
            if self.lighting:color = "\033[31m"
            else:color = ""
        else:
            status = "UNKNOWN"
            if self.lighting:color = "\033[90m"
            else:color = ""
        if self.lighting:reset = "\033[0m"
        else:reset = ""

        self.log.append(f"[{color}{status}{reset}] {current_time} {text}")

    def GetLog(self):
        """You get all the actions you"ve done."""
        result = ""
        for line in self.log:
            result += f"{line}\n"
        return result

    def SaveLog(self, path:str, *, write_type:str="w+", encoding:str="utf-8"):
        """Saving the entire log.
        Write types:
            w;
            w+;"""
        with open(path, write_type, encoding=encoding) as f:
            f.write(self.GetLog())
    
    def SaveToClipboard(self):
        """Saves the log to the clipboard."""
        platform: str = _ss.platform

        if platform == "win32":
            _sb.run("clip", text=True, input=self.GetLog())
        elif platform == "darwin":
            _sb.run("pbcopy", text=True, input=self.GetLog())
        elif platform.startswith("linux"):
            _sb.run("xclip -selection clipboard", text=True, input=self.GetLog())

class MazeGen:
    """Allows you to create a simple maze."""
    def __init__(self, size:tuple | list = (16, 16)):
        """Allows you to create a simple maze."""
        self.size = size
        self.grid = []

    def generate(self):
        """Generates a maze, to get the maze grid, you can use the grid variable."""
        rows, cols = self.size
        self.grid = [[1 for _ in range(cols)] for _ in range(rows)]
        
        start = (1, 1)
        stack = [start]
        self.grid[start[0]][start[1]] = 0
        
        directions = [(-2, 0), (2, 0), (0, -2), (0, 2)]
        
        while stack:
            current = stack[-1]
            x, y = current
            
            neighbors = []
            for dx, dy in directions:
                nx, ny = x + dx, y + dy
                if 1 <= nx < rows-1 and 1 <= ny < cols-1 and self.grid[nx][ny] == 1:
                    neighbors.append((nx, ny, dx, dy))
            
            if neighbors:
                nx, ny, dx, dy = _rn.choice(neighbors)
                self.grid[nx][ny] = 0
                self.grid[x + dx//2][y + dy//2] = 0
                stack.append((nx, ny))
            else:
                stack.pop()
        
        self.grid[rows-2][cols-2] = 0
        return self.grid

class ProgressBar:
    """This class creates a progress bar."""
    def __init__(self, before:str="Loading:", after:str="", maximum:int=5, length:int=20, *, eta:bool=True, percent:bool=True, fillchar:str="█", emptychar:str=" ", borderleft:str="[", borderright:str="]", standardvalue:int=0, fillcolor:str="", emptycolor:str="", borderscolor:str="", defaultcolor:str=""):
        """
        settings:
            before - Text before progressbar;
            after - Text after progressbar;
            maximum - Maximum progress bar value;
            lenght - Length in characters;
            eta - Estimated time until the progress bar is full;
            percent - Shows the percentage of progress bar filled;
            fillchar - Fill symbol;
            emptychar - Symbol of Void;
            borderleft - The left border of the progress bar as a symbol;
            borderright - The right border of the progress bar as a symbol;
            standardvalue - Default value;
            borderscolor - Border color;
            defaultcolor - Default color for text and other;
        Example:
            progress = ProgressBar()
            progress.Show()

            for _ in range(5):
                progress.Add(1)
                time.sleep(0.8)
        """
        self.before, self.after = before, after
        self.max, self.len = maximum, length
        self.eta, self.percent = eta, percent
        self.fill, self.empty = fillchar, emptychar
        self.border_left, self.border_right, self.borders_color = borderleft, borderright, borderscolor
        self.fill_color, self.empty_color = fillcolor, emptycolor
        self.default_color = defaultcolor

        self.value = standardvalue
        self.start_time = _tm.time()

    def Add(self, value:int):
        """Adding value."""
        self.value += value
        self.Show()

    def Show(self):
        """Shows progressbar."""
        chars = ""
        filled = int((self.value / self.max) * self.len)
        
        for _ in range(filled):
            chars += self.fill_color + self.fill
        for _ in range(self.len - filled):
            chars += self.empty_color + self.empty
        
        percent_text = ""
        if self.percent:
            percent_text = f" {self.value / self.max * 100:.1f}% "

        eta_text = ""
        if self.eta and self.value > 0:
            elapsed = _tm.time() - self.start_time
            remaining = (elapsed / self.value) * (self.max - self.value)
            eta_text = f" ETA: {remaining:.1f}s "

        print(f"\r{self.default_color}{self.before}{self.borders_color}{self.border_left}{self.default_color}{chars}{self.borders_color}{self.border_right}{self.default_color}{percent_text}{eta_text}{self.after}", end="")
        _ss.stdout.flush()

