from __future__ import annotations

from dataclasses import dataclass, replace

try:
    from colorama import Fore
except Exception:  # pragma: no cover
    class _Fore:
        BLACK = RED = GREEN = YELLOW = BLUE = MAGENTA = CYAN = WHITE = RESET = ''
        LIGHTBLACK_EX = LIGHTRED_EX = LIGHTGREEN_EX = LIGHTYELLOW_EX = ''
        LIGHTBLUE_EX = LIGHTMAGENTA_EX = LIGHTCYAN_EX = LIGHTWHITE_EX = ''
    Fore = _Fore()


@dataclass
class Theme:
    name: str
    primary: str
    secondary: str
    accent: str
    text: str
    muted: str
    success: str
    warning: str
    danger: str
    border: str
    background: str = ''
    surface: str = ''
    title_glow: str = ''

    def edited(self, **changes: str) -> 'Theme':
        return replace(self, **changes)


THEMES = {
    'dark': Theme('dark', Fore.CYAN, Fore.MAGENTA, Fore.LIGHTCYAN_EX, Fore.WHITE, Fore.LIGHTBLACK_EX, Fore.GREEN, Fore.YELLOW, Fore.RED, Fore.BLUE, surface=Fore.LIGHTBLACK_EX, title_glow=Fore.LIGHTCYAN_EX),
    'light': Theme('light', Fore.BLUE, Fore.MAGENTA, Fore.CYAN, Fore.BLACK, Fore.LIGHTBLACK_EX, Fore.GREEN, Fore.YELLOW, Fore.RED, Fore.CYAN, surface=Fore.WHITE, title_glow=Fore.BLUE),
    'midnight': Theme('midnight', Fore.LIGHTCYAN_EX, Fore.LIGHTBLUE_EX, Fore.MAGENTA, Fore.WHITE, Fore.LIGHTBLACK_EX, Fore.LIGHTGREEN_EX, Fore.LIGHTYELLOW_EX, Fore.LIGHTRED_EX, Fore.BLUE, surface=Fore.LIGHTBLACK_EX, title_glow=Fore.LIGHTMAGENTA_EX),
    'matrix': Theme('matrix', Fore.GREEN, Fore.LIGHTGREEN_EX, Fore.WHITE, Fore.GREEN, Fore.LIGHTBLACK_EX, Fore.LIGHTGREEN_EX, Fore.YELLOW, Fore.RED, Fore.GREEN, surface=Fore.LIGHTBLACK_EX, title_glow=Fore.WHITE),
    'sunset': Theme('sunset', Fore.LIGHTMAGENTA_EX, Fore.YELLOW, Fore.LIGHTRED_EX, Fore.WHITE, Fore.LIGHTBLACK_EX, Fore.GREEN, Fore.YELLOW, Fore.RED, Fore.MAGENTA, surface=Fore.LIGHTBLACK_EX, title_glow=Fore.YELLOW),
    'aurora': Theme('aurora', Fore.LIGHTCYAN_EX, Fore.LIGHTGREEN_EX, Fore.LIGHTMAGENTA_EX, Fore.WHITE, Fore.LIGHTBLACK_EX, Fore.LIGHTGREEN_EX, Fore.LIGHTYELLOW_EX, Fore.LIGHTRED_EX, Fore.CYAN, surface=Fore.LIGHTBLACK_EX, title_glow=Fore.LIGHTGREEN_EX),
    'royal': Theme('royal', Fore.LIGHTMAGENTA_EX, Fore.LIGHTBLUE_EX, Fore.YELLOW, Fore.WHITE, Fore.LIGHTBLACK_EX, Fore.LIGHTGREEN_EX, Fore.LIGHTYELLOW_EX, Fore.LIGHTRED_EX, Fore.MAGENTA, surface=Fore.LIGHTBLACK_EX, title_glow=Fore.YELLOW),
    'frost': Theme('frost', Fore.LIGHTWHITE_EX, Fore.LIGHTCYAN_EX, Fore.BLUE, Fore.WHITE, Fore.LIGHTBLACK_EX, Fore.LIGHTGREEN_EX, Fore.LIGHTYELLOW_EX, Fore.LIGHTRED_EX, Fore.CYAN, surface=Fore.LIGHTBLACK_EX, title_glow=Fore.LIGHTWHITE_EX),
    'neon_night': Theme('neon_night', Fore.LIGHTMAGENTA_EX, Fore.LIGHTCYAN_EX, Fore.LIGHTGREEN_EX, Fore.WHITE, Fore.LIGHTBLACK_EX, Fore.LIGHTGREEN_EX, Fore.LIGHTYELLOW_EX, Fore.LIGHTRED_EX, Fore.LIGHTMAGENTA_EX, surface=Fore.LIGHTBLACK_EX, title_glow=Fore.LIGHTCYAN_EX),
    'rose_gold': Theme('rose_gold', Fore.LIGHTRED_EX, Fore.LIGHTYELLOW_EX, Fore.MAGENTA, Fore.WHITE, Fore.LIGHTBLACK_EX, Fore.LIGHTGREEN_EX, Fore.YELLOW, Fore.RED, Fore.LIGHTRED_EX, surface=Fore.LIGHTBLACK_EX, title_glow=Fore.LIGHTYELLOW_EX),
    'oceanic': Theme('oceanic', Fore.CYAN, Fore.LIGHTBLUE_EX, Fore.LIGHTWHITE_EX, Fore.WHITE, Fore.LIGHTBLACK_EX, Fore.LIGHTGREEN_EX, Fore.LIGHTYELLOW_EX, Fore.LIGHTRED_EX, Fore.BLUE, surface=Fore.LIGHTBLACK_EX, title_glow=Fore.LIGHTCYAN_EX),
    'ember': Theme('ember', Fore.LIGHTRED_EX, Fore.YELLOW, Fore.LIGHTYELLOW_EX, Fore.WHITE, Fore.LIGHTBLACK_EX, Fore.LIGHTGREEN_EX, Fore.YELLOW, Fore.RED, Fore.LIGHTRED_EX, surface=Fore.LIGHTBLACK_EX, title_glow=Fore.YELLOW),
    'orchid': Theme('orchid', Fore.LIGHTMAGENTA_EX, Fore.LIGHTWHITE_EX, Fore.LIGHTCYAN_EX, Fore.WHITE, Fore.LIGHTBLACK_EX, Fore.LIGHTGREEN_EX, Fore.LIGHTYELLOW_EX, Fore.LIGHTRED_EX, Fore.MAGENTA, surface=Fore.LIGHTBLACK_EX, title_glow=Fore.LIGHTWHITE_EX),
}


def get_theme(name: str | None) -> Theme:
    if not name:
        return THEMES['dark']
    return THEMES.get(name.lower(), THEMES['dark'])


class ThemeEditor:
    def __init__(self, theme: Theme):
        self.theme = theme

    def apply(self, **changes: str) -> Theme:
        self.theme = self.theme.edited(**{k: v for k, v in changes.items() if hasattr(self.theme, k)})
        THEMES[self.theme.name] = self.theme
        return self.theme

    def clone(self, name: str) -> Theme:
        new_theme = self.theme.edited(name=name)
        THEMES[name] = new_theme
        return new_theme
