import pathlib

import param

from bokeh.themes import Theme as _BkTheme, _dark_minimal


class Theme(param.Parameterized):
    """
    A Theme customizes the look and feel of a Template by providing
    custom CSS and bokeh Theme class.

    When adding a new theme a generic Theme class should be created,
    which is what users will important and set on the Template.theme
    parameter. Additionally a concrete implementation of the Theme
    should be created specific to the particular Template being used.

    For example when adding a DarkTheme there should be a
    corresponding MaterialDarkTheme which declares the Template class
    on its _template class variable. In this way a user can always use
    the generic Theme but the actual CSS and bokeh Theme will depend
    on the exact Template being used.
    """

    base_css = param.Filename()

    css = param.Filename()

    bokeh_theme = param.ClassSelector(class_=(_BkTheme, str))

    _template = None

    __abstract = True

    @classmethod
    def find_theme(cls, template_type):
        if cls._template is template_type:
            return cls
        for theme in param.concrete_descendents(cls).values():
            if theme._template is template_type:
                return theme


class DefaultTheme(Theme):
    """
    The DefaultTheme uses the standard Panel color palette.
    """

    base_css = param.Filename(default=pathlib.Path(__file__).parent / 'default.css')

    __abstract = True


BOKEH_DARK = dict(_dark_minimal.json)

BOKEH_DARK['attrs']['Figure'].update({
    "background_fill_color": "#3f3f3f",
    "border_fill_color": "#2f2f2f",
})

class DarkTheme(Theme):
    """
    The DefaultTheme uses the standard Panel color palette.
    """

    base_css = param.Filename(default=pathlib.Path(__file__).parent / 'dark.css')

    bokeh_theme = param.ClassSelector(class_=(_BkTheme, str),
                                      default=_BkTheme(json=BOKEH_DARK))

    __abstract = True

THEMES = {
    'default': DefaultTheme,
    'dark': DarkTheme
}
