#-----------------------------------------------------------------------------
# Copyright (c) Anaconda, Inc., and Bokeh Contributors.
# All rights reserved.
#
# The full license is in the file LICENSE.txt, distributed with this software.
#-----------------------------------------------------------------------------

#-----------------------------------------------------------------------------
# Boilerplate
#-----------------------------------------------------------------------------
from __future__ import annotations

import logging # isort:skip
log = logging.getLogger(__name__)

#-----------------------------------------------------------------------------
# Imports
#-----------------------------------------------------------------------------

# Standard library imports
import sys

# Bokeh imports
from ..core.properties import field
from ..models import (
    Circle,
    ColumnarDataSource,
    ColumnDataSource,
    GlyphRenderer,
    MultiLine,
    Scatter,
)
from ._renderer import make_glyph, pop_visuals

#-----------------------------------------------------------------------------
# Globals and constants
#-----------------------------------------------------------------------------

__all__ = (
    'get_graph_kwargs'
)

RENDERER_ARGS = ['name', 'level', 'visible', 'x_range_name', 'y_range_name',
                 'selection_policy', 'inspection_policy']

#-----------------------------------------------------------------------------
# General API
#-----------------------------------------------------------------------------

#-----------------------------------------------------------------------------
# Dev API
#-----------------------------------------------------------------------------

def get_graph_kwargs(node_source: ColumnDataSource, edge_source: ColumnDataSource, **kwargs) -> dict:

    if not isinstance(node_source, ColumnarDataSource):
        try:
            node_source = ColumnDataSource(node_source)
        except ValueError as err:
            msg = f"Failed to auto-convert {type(node_source)} to ColumnDataSource.\n Original error: {err}"
            raise ValueError(msg).with_traceback(sys.exc_info()[2])

    if not isinstance(edge_source, ColumnarDataSource):
        try:
            edge_source = ColumnDataSource(edge_source)
        except ValueError as err:
            msg = f"Failed to auto-convert {type(edge_source)} to ColumnDataSource.\n Original error: {err}"
            raise ValueError(msg).with_traceback(sys.exc_info()[2])

    marker = kwargs.pop('node_marker', None)
    marker_type = Scatter
    if isinstance(marker, dict) and 'field' in marker or marker in node_source.data:
        kwargs['node_marker'] = field(marker)
    else:
        if isinstance(marker, dict) and 'value' in marker:
            marker = marker['value']

        if marker is None or marker == "circle":
            if "node_radius" in kwargs:
                marker_type = Circle
            else:
                marker_type = Scatter
        else:
            kwargs["node_marker"] = marker

    ## node stuff
    node_visuals = pop_visuals(marker_type, kwargs, prefix="node_")

    if any(x.startswith('node_selection_') for x in kwargs):
        snode_visuals = pop_visuals(marker_type, kwargs, prefix="node_selection_", defaults=node_visuals)
    else:
        snode_visuals = None

    if any(x.startswith('node_hover_') for x in kwargs):
        hnode_visuals = pop_visuals(marker_type, kwargs, prefix="node_hover_", defaults=node_visuals)
    else:
        hnode_visuals = None

    mnode_visuals = pop_visuals(marker_type, kwargs, prefix="node_muted_", defaults=node_visuals, override_defaults={'alpha':0.2})

    nsnode_visuals = pop_visuals(marker_type, kwargs, prefix="node_nonselection_", defaults=node_visuals)

    ## edge stuff
    edge_visuals = pop_visuals(MultiLine, kwargs, prefix="edge_")

    if any(x.startswith('edge_selection_') for x in kwargs):
        sedge_visuals = pop_visuals(MultiLine, kwargs, prefix="edge_selection_", defaults=edge_visuals)
    else:
        sedge_visuals = None

    if any(x.startswith('edge_hover_') for x in kwargs):
        hedge_visuals = pop_visuals(MultiLine, kwargs, prefix="edge_hover_", defaults=edge_visuals)
    else:
        hedge_visuals = None

    medge_visuals = pop_visuals(MultiLine, kwargs, prefix="edge_muted_", defaults=edge_visuals, override_defaults={'alpha':0.2})

    nsedge_visuals = pop_visuals(MultiLine, kwargs, prefix="edge_nonselection_", defaults=edge_visuals)

    ## node stuff
    node_kwargs = {k.lstrip('node_'): v for k, v in kwargs.copy().items() if k.lstrip('node_') in marker_type.properties()}

    node_glyph = make_glyph(marker_type, node_kwargs, node_visuals)
    nsnode_glyph = make_glyph(marker_type, node_kwargs, nsnode_visuals)
    snode_glyph = make_glyph(marker_type, node_kwargs, snode_visuals)
    hnode_glyph = make_glyph(marker_type, node_kwargs, hnode_visuals)
    mnode_glyph = make_glyph(marker_type, node_kwargs, mnode_visuals)

    node_renderer = GlyphRenderer(
        data_source=node_source,
        glyph=node_glyph,
        selection_glyph=snode_glyph or "auto",
        nonselection_glyph=nsnode_glyph or "auto",
        hover_glyph=hnode_glyph,
        muted_glyph=mnode_glyph or "auto",
    )

    ## edge stuff
    edge_kwargs = {k.lstrip('edge_'): v for k, v in kwargs.copy().items() if k.lstrip('edge_') in MultiLine.properties()}

    edge_glyph = make_glyph(MultiLine, edge_kwargs, edge_visuals)
    nsedge_glyph = make_glyph(MultiLine, edge_kwargs, nsedge_visuals)
    sedge_glyph = make_glyph(MultiLine, edge_kwargs, sedge_visuals)
    hedge_glyph = make_glyph(MultiLine, edge_kwargs, hedge_visuals)
    medge_glyph = make_glyph(MultiLine, edge_kwargs, medge_visuals)

    edge_renderer = GlyphRenderer(
        data_source=edge_source,
        glyph=edge_glyph,
        selection_glyph=sedge_glyph or "auto",
        nonselection_glyph=nsedge_glyph or "auto",
        hover_glyph=hedge_glyph,
        muted_glyph=medge_glyph or "auto",
    )

    renderer_kwargs = {attr: kwargs.pop(attr) for attr in RENDERER_ARGS if attr in kwargs}

    renderer_kwargs["node_renderer"] = node_renderer
    renderer_kwargs["edge_renderer"] = edge_renderer

    return renderer_kwargs

#-----------------------------------------------------------------------------
# Private API
#-----------------------------------------------------------------------------

#-----------------------------------------------------------------------------
# Code
#-----------------------------------------------------------------------------
