import base64

from dash import dcc, callback, Output, Input, no_update

import dash_bootstrap_components as dbc

from inspect import stack
from logging import Logger, getLogger

from dash import html
from urllib.parse import unquote

from com_enovation.toolbox.dash.session import Session
from com_enovation.toolbox.dash.sheet import Sheet, SheetAsDiv
from com_enovation.toolbox.dash.widget import Widget


class NavigationAsNavbar(Widget, dbc.Navbar):

    _logger: Logger = getLogger(__name__)

    # ##################################################################################################################
    # CONSTANTS
    # ##################################################################################################################

    const_str_default_navbar_brand: str = "eNOVAtion"
    const_str_default_str_logo: str = "images/com-enovation.square.png"

    # The labels in the configuration file
    const_str__config_label__dict_properties: str = "properties"
    const_str__config_label__str_navbar_brand: str = "navbar_brand"
    const_str__config_label__url_logo: str = "logo"
    const_str__config_label__str_title: str = "title"

    # The wid for the default generic widgets
    const_str__wid__div_debug: str = "debug"
    const_str__wid__location_url: str = "url"
    const_str__wid__navbar_header: str = "header"

    """ 
    Return the navigation bar, along with the callback function to load the enov-content__as_main part
    - An image as the logo
    - A brand, which is used as well as the title for the logo
    - Menus to various widgets available.

    The produced HTML is of this kind:
    <nav id="enov-header__as_navbar" class="fixed-top navbar navbar-expand-md navbar-dark bg-dark">
        <div class="nav-item">
            <a href="https://pypi.org/project/com-enovation/">
                <div class="align-items-center row">
                    <div class="col">
                        <img height="30px" src="/assets/images/com-enovation.square.png" title="com.enovation">
                    </div>
                    <div class="col">
                        <span class="navbar-brand">eNOVAtion</span>
                    </div>
                </div>
            </a>
        </div>
        <div class="nav-item">
            <a href="#welcome" class="nav-link">welcome</a>
        </div>
        <div class="nav-item">
            <a href="#explore" class="nav-link">explore</a>
        </div>
        <div class="nav-item">
            <a class="nav-link disabled" disabled="">The default dp_grapher for date predictability module...</a>
        </div>
    </nav>        
    """

    def __init__(
            self,
            dict_sheet: dict[str, Sheet],
            dict_config: dict,
            dict_context: dict,
            str__wid__main_content: str,
            session: Session
    ):

        self._logger.debug(f"Function '{stack()[0].filename} - {stack()[0].function}' is called.")

        _str_the_title: str = dict_config.get(
            self.const_str__config_label__dict_properties, {}
        ).get(self.const_str__config_label__str_title, self.const_str_default_navbar_brand)

        if self.const_str__config_label__url_logo in dict_config.get(
                self.const_str__config_label__dict_properties, {}
        ):
            _img_the_logo: html.Img = html.Img(
                src='data:image/png;base64,{}'.format(
                    base64.b64encode(
                        open(
                            dict_config[
                                self.const_str__config_label__dict_properties
                            ][
                                self.const_str__config_label__url_logo
                            ],
                            'rb'
                        ).read()
                    )
                ),
                height="30px",
                title=_str_the_title
            )
        else:
            _img_the_logo: html.Img = html.Img(
                src=session.dash_application.dash_server.get_asset_url(self.const_str_default_str_logo),
                height="30px",
                title=_str_the_title
            )

        Widget.__init__(
            self,
            dict_config=dict_config,
            dict_context=dict_context,
            session=session
        )

        dbc.Navbar.__init__(
            self,
            children=[
                # To get the url loaded
                dcc.Location(id=self.const_str__wid__location_url),

                dbc.NavItem(
                    html.A(
                        dbc.Row(
                            [
                                dbc.Col(_img_the_logo),
                                dbc.Col(
                                    dbc.NavbarBrand(dict_config.get(
                                        self.const_str__config_label__dict_properties, {}
                                    ).get(
                                        self.const_str__config_label__str_navbar_brand,
                                        self.const_str_default_navbar_brand)
                                    )
                                ),
                            ],
                            align="center",
                        ),
                        href="https://pypi.org/project/com-enovation/"
                    )
                )
            ] + [
                dbc.NavItem(dbc.NavLink(i_widget, href="#"+i_widget))
                for i_widget in dict_sheet
            ] + [
                dbc.NavItem(dbc.NavLink("The default dp_grapher for the date predictability module...", disabled=True))
            ],
            color="dark",
            dark=True,
            id=self.const_str__wid__navbar_header,
            className="fixed-top"
        )

        @callback(
            Output(str__wid__main_content, 'children'),
            Input(self.const_str__wid__location_url, 'hash'),
            prevent_initial_call=True
        )
        def _callback_navigate_and_load_content(url_hash: str) -> html.Div:
            """
            Callback function:
            - When we click in a menu in the navigation bar, it refreshes the page with an updated URL
              "https://xxx/#whatever"
            - When such URL update happens, the widget "url as location" is refreshed
            - Using this refresh, we load the area "content as main" with the new target widget.

            :param url_hash: the link to an element with a specified id within the page
            :return: the widget to load in the area "content as main"
            """
            getLogger(__name__).debug(f"Function '{stack()[0].filename} - {stack()[0].function}' is called.")

            if url_hash == '':
                return no_update

            _dict_the_sheets: dict[str, SheetAsDiv] = self.session.dash_application.dict_sheets

            if unquote(url_hash)[1:] not in _dict_the_sheets:
                raise Exception(f"Unexpected url_hash '{unquote(url_hash)}'.")

            div_the_return: html.Div = _dict_the_sheets[unquote(url_hash)[1:]]

            self.session.debug(
                debug_trace=f"Click navigation menus to update main content: {unquote(url_hash)}, returned an "
                            f"object of type '{type(div_the_return)}'"
            )

            getLogger(__name__).debug(f"Function '{stack()[0].filename} - {stack()[0].function}' is returning.")

            return div_the_return

        self._logger.debug(f"Function '{stack()[0].filename} - {stack()[0].function}' is returning.")
