import os

if os.name == 'nt':
    try:
        import ctypes
        kernel32 = ctypes.windll.kernel32
        kernel32.SetConsoleMode(kernel32.GetStdHandle(-11), 7)
    except Exception as e:
        print("Could not enable ANSI support:", e)

class ANSI:
    CSI = '\033['
    RESET = f"{CSI}0m"

class ANSIBase:
    def __getattr__(self, name: str) -> str:
        """Dynamically retrieve color, background, or style by name."""
        return self._entries.get(name.upper(), ANSI.RESET)

    def add_entry(self, name: str, code: str):
        """Add a new entry to colors, backgrounds, or styles."""
        self._entries[name.upper()] = code


class Colors(ANSIBase):
    _entries = {
        'BLACK': f"{ANSI.CSI}30m", 'RED': f"{ANSI.CSI}31m", 'GREEN': f"{ANSI.CSI}32m",
        'YELLOW': f"{ANSI.CSI}33m", 'BLUE': f"{ANSI.CSI}34m", 'MAGENTA': f"{ANSI.CSI}35m",
        'CYAN': f"{ANSI.CSI}36m", 'WHITE': f"{ANSI.CSI}37m",
        'LIGHT_BLACK': f"{ANSI.CSI}90m", 'LIGHT_RED': f"{ANSI.CSI}91m", 'LIGHT_GREEN': f"{ANSI.CSI}92m",
        'LIGHT_YELLOW': f"{ANSI.CSI}93m", 'LIGHT_BLUE': f"{ANSI.CSI}94m", 'LIGHT_MAGENTA': f"{ANSI.CSI}95m",
        'LIGHT_CYAN': f"{ANSI.CSI}96m", 'LIGHT_WHITE': f"{ANSI.CSI}97m",
        'ORANGE': f"{ANSI.CSI}38;5;208m", 'BRIGHT_RED': f"{ANSI.CSI}38;5;196m",
        'FOREST_GREEN': f"{ANSI.CSI}38;5;34m", 'DARK_GREEN': f"{ANSI.CSI}38;5;22m",
        'DARK_RED': f"{ANSI.CSI}38;5;88m", 'PEACH': f"{ANSI.CSI}38;5;210m",
        'PASTEL_YELLOW': f"{ANSI.CSI}38;5;228m", 'PASTEL_GREEN': f"{ANSI.CSI}38;5;120m",
        'PASTEL_PURPLE': f"{ANSI.CSI}38;5;141m", 'BURNT_ORANGE': f"{ANSI.CSI}38;5;130m",
        'ELECTRIC_BLUE': f"{ANSI.CSI}38;5;45m", 'BRIGHT_PINK': f"{ANSI.CSI}38;5;201m",
        'BRIGHT_ORANGE': f"{ANSI.CSI}38;5;214m", 'BRIGHT_TEAL': f"{ANSI.CSI}38;5;51m",
        'OLIVE': f"{ANSI.CSI}38;5;100m", 'DARK_SLATE': f"{ANSI.CSI}38;5;235m",
        'SOFT_LAVENDER': f"{ANSI.CSI}38;5;183m", 'SOFT_PINK': f"{ANSI.CSI}38;5;217m",
        'LIGHT_SKY_BLUE': f"{ANSI.CSI}38;5;153m", 'PALE_MINT_GREEN': f"{ANSI.CSI}38;5;121m",
        'GRAY_3': f"{ANSI.CSI}38;5;237m", 'GRAY_7': f"{ANSI.CSI}38;5;243m",
        'GRAY_11': f"{ANSI.CSI}38;5;247m", 'NEON_GREEN': f"{ANSI.CSI}38;5;46m",
        'NEON_YELLOW': f"{ANSI.CSI}38;5;226m"
    }


class Backgrounds(ANSIBase):
    _entries = {
        'BLACK': f"{ANSI.CSI}40m", 'RED': f"{ANSI.CSI}41m", 'GREEN': f"{ANSI.CSI}42m",
        'YELLOW': f"{ANSI.CSI}43m", 'BLUE': f"{ANSI.CSI}44m", 'MAGENTA': f"{ANSI.CSI}45m",
        'CYAN': f"{ANSI.CSI}46m", 'WHITE': f"{ANSI.CSI}47m",
        'LIGHT_BLACK': f"{ANSI.CSI}100m", 'LIGHT_RED': f"{ANSI.CSI}101m",
        'LIGHT_GREEN': f"{ANSI.CSI}102m", 'LIGHT_YELLOW': f"{ANSI.CSI}103m",
        'LIGHT_BLUE': f"{ANSI.CSI}104m", 'LIGHT_MAGENTA': f"{ANSI.CSI}105m",
        'LIGHT_CYAN': f"{ANSI.CSI}106m", 'LIGHT_WHITE': f"{ANSI.CSI}107m"
    }


class Styles(ANSIBase):
    _entries = {
        'BOLD': f"{ANSI.CSI}1m", 'DIM': f"{ANSI.CSI}2m", 'ITALIC': f"{ANSI.CSI}3m",
        'UNDERLINE': f"{ANSI.CSI}4m", 'BLINK': f"{ANSI.CSI}5m", 'REVERSE': f"{ANSI.CSI}7m",
        'HIDDEN': f"{ANSI.CSI}8m", 'RESET': ANSI.RESET
    }

Rcolor = Colors()
Rbackground = Backgrounds()
Rstyle = Styles()


def color_text(text: str, color: str = "", background: str = "", style: str = "") -> str:
    """Applies color, background, and style to text."""
    return f"{color}{background}{style}{text}{Rstyle.RESET}"

"""
print(f"{Rcolor.CYAN}This is cyan text{Rstyle.RESET}")
print(f"{Rstyle.BOLD}{Rcolor.RED}Bold Red Text{Rstyle.RESET}")
print(f"{Rbackground.LIGHT_BLUE}{Rcolor.WHITE}White on Light Blue Background{Rstyle.RESET}")

Rcolor.add_entry('CUSTOM_PURPLE', f"{ANSI.CSI}38;5;93m") # add customs colors, background and styles
Rbackground.add_entry('CUSTOM_BG_PURPLE', f"{ANSI.CSI}48;5;93m")
Rstyle.add_entry('DOUBLE_UNDERLINE', f"{ANSI.CSI}21m")

print(f"{Rcolor.CUSTOM_PURPLE}Custom Purple Text{Rstyle.RESET}")
print(f"{Rbackground.CUSTOM_BG_PURPLE}Text with Custom Purple Background{Rstyle.RESET}")
print(f"{Rstyle.DOUBLE_UNDERLINE}Double Underlined Text{Rstyle.RESET}")
"""
