"""
Various visualization routines, mostly to help development for now
"""
from typing import TYPE_CHECKING, Optional, List, TypedDict, Union
from rich import print
import random

from dash import Dash, html
import dash_cytoscape as cyto
cyto.load_extra_layouts()

from nwb_schema_language import Namespace, Group, Dataset
from nwb_linkml.io import load_nwb_core

if TYPE_CHECKING:
    from nwb_linkml.adapters import NamespacesAdapter
    # from nwb_schema_language.datamodel import Namespaces

class _CytoNode(TypedDict):
    id: str
    label: str

class _CytoEdge(TypedDict):
    source: str
    target: str

class CytoElement(TypedDict):
    data: _CytoEdge | _CytoNode
    classes: Optional[str]

class Node:
    def __init__(self,
                 id: str,
                 label: str,
                 klass: str,
                 parent: Optional[str] = None):
        self.id = id
        self.label = label
        self.parent = parent
        self.klass = klass

    def make(self) -> List[CytoElement]:

        node = [
            CytoElement(data= _CytoNode(id=self.id, label=self.label), classes=self.klass)
        ]
        if self.parent:
            edge = [
                CytoElement(data=_CytoEdge(source=self.parent, target=self.id))
            ]
            node += edge

        return node

def make_node(element: Group | Dataset, parent=None, recurse:bool=True) -> List[Node]:
    if element.neurodata_type_def is None:
        if element.name is None:
            if element.neurodata_type_inc is None:
                name = 'anonymous'
            else:
                name = element.neurodata_type_inc
        else:
            name = element.name
        id = name + '-' + str(random.randint(0,1000))
        label = id
        classname = str(type(element).__name__).lower() + '-child'
    else:
        id = element.neurodata_type_def
        label = element.neurodata_type_def
        classname = str(type(element).__name__).lower()

    if parent is None:
        parent = element.neurodata_type_inc


    node = Node(
        id=id,
        label=label,
        parent=parent,
        klass=classname
    )
    nodes = [node]

    if isinstance(element, Group) and recurse:
        for group in element.groups:
            nodes += make_node(group, parent=id)
        for dataset in element.datasets:
            nodes += make_node(dataset, parent=id)
    return nodes


def make_graph(namespaces: 'NamespacesAdapter', recurse:bool=True) -> List[CytoElement]:
    namespaces.populate_imports()
    nodes = []
    element: Namespace | Group | Dataset
    print('walking graph')
    i = 0
    for element in namespaces.walk_types(namespaces, (Group, Dataset)):
        if element.neurodata_type_def is None:
            # skip child nodes at top level, we'll get them in recursion
            continue
        if any([element.neurodata_type_def == node.id for node in nodes]):
            continue
        nodes.extend(make_node(element, recurse=recurse))

    print('making elements')
    cytoelements = []
    for node in nodes:
        cytoelements += node.make()
    print(cytoelements)
    return cytoelements

def plot_dependency_graph(namespaces: 'NamespacesAdapter', recurse:bool=True) -> Dash:
    graph = make_graph(namespaces, recurse=recurse)

    app = Dash(__name__)

    styles = [
        {
            'selector': 'node',
            'style': {
                'content': 'data(label)'
            }
        },
        {
            'selector': '.dataset',
            'style': {
                'background-color': 'red',
                'shape': 'rectangle'
            }
        },
        {
            'selector': '.group',
            'style': {
                'background-color': 'blue',
                'shape': 'rectangle'
            }
        },
        {
            'selector': '.dataset-child',
            'style': {
                'background-color': 'red'
            }
        },
        {
            'selector': '.group-child',
            'style': {
                'background-color': 'blue'
            }
        }
    ]

    app.layout = html.Div([
        cyto.Cytoscape(
            id='nwb_graph',
            elements = graph,
            style={'width': '100%', 'height': '100vh'},
            layout= {'name': 'klay', 'rankDir': 'LR'},
            stylesheet=styles
        )
    ])
    return app

if __name__ == "__main__":
    core = load_nwb_core()
    app = plot_dependency_graph(core, recurse=True)
    print('opening dash')
    app.run(debug=True)


