"""
Cross-platform color text printing
"""
import sys

try:
    from colorama.win32 import windll
    from colorama.winterm import WinColor, WinStyle, WinTerm
except ImportError:
    windll = None

    class WinColor:
        BLACK = 0
        RED = 1
        GREEN = 2
        YELLOW = 3
        BLUE = 4
        MAGENTA = 5
        CYAN = 6
        GREY = 7

    class WinStyle:
        NORMAL = 0
        BRIGHT = 1

    class WinTerm:
        def reset_all(self):
            pass

        def fore(self, *args):
            pass

        def back(self, *args):
            pass

        def style(self, *args):
            pass


_WIN = sys.platform.startswith('win')
if windll is not None:
    winterm = WinTerm()
else:
    _WIN = False

def winset(
    reset: bool = False,
    fore: WinColor | None = None,
    back: WinColor | None = None,
    style: WinStyle | None = None,
    stderr: bool = False
):
    if reset:
        winterm.reset_all()
    if fore is not None:
        winterm.fore(fore, stderr)
    if back is not None:
        winterm.back(back, stderr)
    if style is not None:
        winterm.style(style, stderr)

ANSI = {}
WIN = {}
for i, color in enumerate(
    ['BLACK', 'RED', 'GREEN', 'YELLOW', 'BLUE', 'MAGENTA', 'CYAN', 'WHITE']
):
    globals()[color] = i
    globals()[f'BR_{color}'] = i + 8
    globals()[f'BACK_{color}'] = i + 40
    ANSI[i] = "\033[%dm" % (30+i)
    ANSI[i+8] = "\033[2;%dm" % (30+i)
    ANSI[i+40] = "\033[%dm" % (40+i)
    color = 'GREY' if color == 'WHITE' else color
    WIN[i] = {'fore': getattr(WinColor, color), 'style': WinStyle.NORMAL}
    WIN[i+8] = {'fore': getattr(WinColor, color), 'style': WinStyle.BRIGHT}
    WIN[i+40] = {'back': getattr(WinColor, color)}

RESET = -1
ANSI[RESET] = "\033[0m"
WIN[RESET] =  {'reset': True}


def cprint(stream, *args, **kwds):
    """
    Print with color. Examples::

        # colors are BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE
        cprint('stdout', RED, 'This is in red. ', RESET, 'and this is normal\n')

        # Adding BR_ before the color manes it bright
        cprint('stdout', BR_GREEN, 'This is bright green.\n', RESET)

        # Adding BACK_ changes background color
        cprint('stderr', BACK_BLUE, WHITE, 'This is white-on-blue.', -1)

        # Integers 0-7 for normal, 8-15 for bright, and 40-47 for background.
        # -1 to reset.
        cprint('stderr', 1, 'This is in red.', -1)

    """
    if isinstance(stream, str):
        stream = kwds.get('stream', 'stdout')
        err = stream == 'stderr'
        stream = getattr(sys, stream)
    else:
        err = kwds.get('stderr', False)

    if hasattr(stream, 'isatty') and stream.isatty():
        for arg in args:
            if isinstance(arg, str):
                stream.write(arg)
            elif _WIN:
                kwds = WIN[arg]
                winset(stderr=err, **kwds)
            else:
                stream.write(ANSI[arg])
    else:
        # ignore colors
        for arg in args:
            if isinstance(arg, str):
                stream.write(arg)

def cout(*args):
    """Shorthand for cprint('stdout', ...)"""
    cprint('stdout', *args)

def cerr(*args):
    """Shorthand for cprint('stderr', ...)"""
    cprint('stderr', *args)
