import sys
import os
import json


class ThemeManager:

    theme = {}  # contains all the theme data
    built_in_themes = ["blue", "green", "dark-blue", "sweetkind"]

    @classmethod
    def load_theme(cls, theme_name_or_path: str):
        script_directory = os.path.dirname(os.path.abspath(__file__))

        if theme_name_or_path in cls.built_in_themes:
            with open(os.path.join(script_directory, "assets", "themes", f"{theme_name_or_path}.json"), "r") as f:
                cls.theme = json.load(f)
        else:
            with open(theme_name_or_path, "r") as f:
                cls.theme = json.load(f)

        if sys.platform == "darwin":
            cls.theme["text"] = cls.theme["text"]["macOS"]
        elif sys.platform.startswith("win"):
            cls.theme["text"] = cls.theme["text"]["Windows"]
        else:
            cls.theme["text"] = cls.theme["text"]["Linux"]

    @staticmethod
    def single_color(color, appearance_mode: int) -> str:
        """ color can be either a single hex color string or a color name or it can be a
            tuple color with (light_color, dark_color). The functions then returns
            always a single color string """

        if type(color) == tuple or type(color) == list:
            return color[appearance_mode]
        else:
            return color

    @staticmethod
    def rgb2hex(rgb_color: tuple) -> str:
        return "#{:02x}{:02x}{:02x}".format(round(rgb_color[0]), round(rgb_color[1]), round(rgb_color[2]))

    @staticmethod
    def hex2rgb(hex_color: str) -> tuple:
        return tuple(int(hex_color.strip("#")[i:i+2], 16) for i in (0, 2, 4))

    @classmethod
    def linear_blend(cls, color_1: str, color_2: str, blend_factor: float) -> str:
        """ Blends two hex colors linear, where blend_factor of 0
            results in color_1 and blend_factor of 1 results in color_2. """

        if color_1 is None or color_2 is None:
            return None

        rgb_1 = cls.hex2rgb(color_1)
        rgb_2 = cls.hex2rgb(color_2)

        new_rgb = (rgb_1[0] + (rgb_2[0] - rgb_1[0]) * blend_factor,
                   rgb_1[1] + (rgb_2[1] - rgb_1[1]) * blend_factor,
                   rgb_1[2] + (rgb_2[2] - rgb_1[2]) * blend_factor)

        return cls.rgb2hex(new_rgb)

    @classmethod
    def get_minimal_darker(cls, color: str) -> str:
        if color.startswith("#"):
            color_rgb = cls.hex2rgb(color)
            if color_rgb[0] > 0:
                return cls.rgb2hex((color_rgb[0] - 1, color_rgb[1], color_rgb[2]))
            elif color_rgb[1] > 0:
                return cls.rgb2hex((color_rgb[0], color_rgb[1] - 1, color_rgb[2]))
            elif color_rgb[2] > 0:
                return cls.rgb2hex((color_rgb[0], color_rgb[1], color_rgb[2] - 1))
            else:
                return cls.rgb2hex((color_rgb[0] + 1, color_rgb[1], color_rgb[2] - 1))  # otherwise slightly lighter

    @classmethod
    def multiply_hex_color(cls, hex_color: str, factor: float = 1.0) -> str:
        try:
            rgb_color = ThemeManager.hex2rgb(hex_color)
            dark_rgb_color = (min(255, rgb_color[0] * factor),
                              min(255, rgb_color[1] * factor),
                              min(255, rgb_color[2] * factor))
            return ThemeManager.rgb2hex(dark_rgb_color)
        except Exception as err:
            # sys.stderr.write("ERROR (CTkColorManager): failed to darken the following color: " + str(hex_color) + " " + str(err))
            return hex_color

    @classmethod
    def set_main_color(cls, main_color, main_color_hover):
        cls.MAIN_COLOR = main_color
        cls.MAIN_HOVER_COLOR = main_color_hover