import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
from pynwb import TimeSeries
from datetime import datetime
from dateutil.tz import tzlocal
from pynwb import NWBFile
from ipywidgets import widgets
from pynwb.core import DynamicTable
from pynwb.file import Subject
from nwbwidgets.view import default_neurodata_vis_spec
from pynwb import ProcessingModule
from pynwb.behavior import Position, SpatialSeries
from nwbwidgets.base import show_neurodata_base,processing_module, nwb2widget, show_text_fields, \
fig2widget, vis2widget, show_fields, show_dynamic_table, df2accordion, lazy_show_over_data
import unittest
import pytest
    
    
def test_show_neurodata_base():
    start_time = datetime(2017, 4, 3, 11, tzinfo=tzlocal())
    create_date = datetime(2017, 4, 15, 12, tzinfo=tzlocal())
    
    nwbfile = NWBFile(session_description='demonstrate NWBFile basics',  
                      identifier='NWB123',  
                      session_start_time=start_time,  
                      file_create_date=create_date,
                      related_publications='https://doi.org/10.1088/1741-2552/aaa904',
                      experimenter='Dr. Pack')
    
    assert isinstance(show_neurodata_base(nwbfile,default_neurodata_vis_spec), widgets.Widget)
    

def test_show_text_fields():
    data = np.random.rand(160,3)
    ts = TimeSeries(name='test_timeseries', data=data, unit='m', starting_time=0.0, rate=1.0)
    assert isinstance(show_text_fields(ts), widgets.Widget)
    
    
class ProcessingModuleTestCase(unittest.TestCase):
    
    def setUp(self):
        spatial_series = SpatialSeries(name='position',
                                   data=np.linspace(0, 1, 20),
                                   rate=50.,
                                   reference_frame='starting gate')
        self.position = Position(spatial_series=spatial_series)
    
    def test_processing_module(self):

        start_time = datetime(2020, 1, 29, 11, tzinfo=tzlocal())
        nwbfile = NWBFile(session_description='Test Session',  
                      identifier='NWBPM',  
                      session_start_time=start_time)

        behavior_module = ProcessingModule(name='behavior',
                                                       description='preprocessed behavioral data')
        nwbfile.add_processing_module(behavior_module)

        nwbfile.processing['behavior'].add(self.position)

        processing_module(nwbfile.processing['behavior'], default_neurodata_vis_spec)

    def test_nwb2widget(self):

        nwb2widget(self.position, default_neurodata_vis_spec)


def test_fig2widget():
    
    data = np.random.rand(160, 3)
    fig = plt.figure(figsize=(10, 5))
    plt.plot(data)
    
    assert isinstance(fig2widget(fig), widgets.Widget)


class Test_vis2widget:
    def test_vis2widget_input_widget(self):

        wg = widgets.IntSlider(
            value=7,
            min=0,
            max=10,
            step=1,
            description='Test:',
            disabled=False,
            continuous_update=False,
            orientation='horizontal',
            readout=True,
            readout_format='d')

        assert isinstance(vis2widget(wg), widgets.Widget)

    def test_vis2widget_input_figure(self):

        data = np.random.rand(160,3)

        fig=plt.figure(figsize=(10, 5))
        plt.plot(data)

        assert isinstance(vis2widget(fig), widgets.Widget)
        
    def test_vis2widget_input_other(self):
        data = np.random.rand(160,3)
        with pytest.raises(ValueError, match="unsupported vis type"):
            vis2widget(data)


def test_show_subject():
    node = Subject(age='8', sex='m', species='macaque')
    show_fields(node)


def test_show_dynamic_table():
    d = {'col1': [1, 2], 'col2': [3, 4]}
    DT = DynamicTable.from_dataframe(df=pd.DataFrame(data=d), 
                                     name='Test Dtable', 
                                     table_description='no description')
    show_dynamic_table(DT)


def test_df2accordion():
    df = pd.DataFrame(np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]),
                     columns=['a', 'b', 'c'])
    def func_fig(data):
        fig=plt.figure(figsize=(10, 5))
        plt.plot(data)
        return fig
    df2accordion(df=df,by='a',func=func_fig)
    
    
def test_df2accordion_single():
    df = pd.DataFrame(np.array([1]),
                     columns=['a'])
    def func_fig(data):
        fig=plt.figure(figsize=(10, 5))
        plt.plot(data)
        return fig
    df2accordion(df=df,by='a',func=func_fig)
    
    
def test_lazy_show_over_data():
    list_ = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
    def func_fig(data):
        fig=plt.figure(figsize=(10, 5))
        plt.plot(data)
        return fig
    assert isinstance(lazy_show_over_data(list_=list_,func_=func_fig),widgets.Widget)

[((24, 14, 29, 46), 'pynwb.NWBFile', 'NWBFile', (), '', False, 'from pynwb import NWBFile\n'), ((35, 11, 35, 32), 'numpy.random.rand', 'np.random.rand', ({(35, 26, 35, 29): '160', (35, 30, 35, 31): '3'}, {}), '(160, 3)', True, 'import numpy as np\n'), ((36, 9, 36, 93), 'pynwb.TimeSeries', 'TimeSeries', (), '', False, 'from pynwb import TimeSeries\n'), ((71, 11, 71, 33), 'numpy.random.rand', 'np.random.rand', ({(71, 26, 71, 29): '160', (71, 31, 71, 32): '3'}, {}), '(160, 3)', True, 'import numpy as np\n'), ((72, 10, 72, 37), 'matplotlib.pyplot.figure', 'plt.figure', (), '', True, 'import matplotlib.pyplot as plt\n'), ((73, 4, 73, 18), 'matplotlib.pyplot.plot', 'plt.plot', ({(73, 13, 73, 17): 'data'}, {}), '(data)', True, 'import matplotlib.pyplot as plt\n'), ((111, 11, 111, 55), 'pynwb.file.Subject', 'Subject', (), '', False, 'from pynwb.file import Subject\n'), ((112, 4, 112, 21), 'nwbwidgets.base.show_fields', 'show_fields', ({(112, 16, 112, 20): 'node'}, {}), '(node)', False, 'from nwbwidgets.base import show_neurodata_base, processing_module, nwb2widget, show_text_fields, fig2widget, vis2widget, show_fields, show_dynamic_table, df2accordion, lazy_show_over_data\n'), ((120, 4, 120, 26), 'nwbwidgets.base.show_dynamic_table', 'show_dynamic_table', ({(120, 23, 120, 25): 'DT'}, {}), '(DT)', False, 'from nwbwidgets.base import show_neurodata_base, processing_module, nwb2widget, show_text_fields, fig2widget, vis2widget, show_fields, show_dynamic_table, df2accordion, lazy_show_over_data\n'), ((130, 4, 130, 44), 'nwbwidgets.base.df2accordion', 'df2accordion', (), '', False, 'from nwbwidgets.base import show_neurodata_base, processing_module, nwb2widget, show_text_fields, fig2widget, vis2widget, show_fields, show_dynamic_table, df2accordion, lazy_show_over_data\n'), ((140, 4, 140, 44), 'nwbwidgets.base.df2accordion', 'df2accordion', (), '', False, 'from nwbwidgets.base import show_neurodata_base, processing_module, nwb2widget, show_text_fields, fig2widget, vis2widget, show_fields, show_dynamic_table, df2accordion, lazy_show_over_data\n'), ((31, 22, 31, 77), 'nwbwidgets.base.show_neurodata_base', 'show_neurodata_base', ({(31, 42, 31, 49): 'nwbfile', (31, 50, 31, 76): 'default_neurodata_vis_spec'}, {}), '(nwbfile, default_neurodata_vis_spec)', False, 'from nwbwidgets.base import show_neurodata_base, processing_module, nwb2widget, show_text_fields, fig2widget, vis2widget, show_fields, show_dynamic_table, df2accordion, lazy_show_over_data\n'), ((37, 22, 37, 42), 'nwbwidgets.base.show_text_fields', 'show_text_fields', ({(37, 39, 37, 41): 'ts'}, {}), '(ts)', False, 'from nwbwidgets.base import show_neurodata_base, processing_module, nwb2widget, show_text_fields, fig2widget, vis2widget, show_fields, show_dynamic_table, df2accordion, lazy_show_over_data\n'), ((47, 24, 47, 63), 'pynwb.behavior.Position', 'Position', (), '', False, 'from pynwb.behavior import Position, SpatialSeries\n'), ((52, 18, 54, 52), 'pynwb.NWBFile', 'NWBFile', (), '', False, 'from pynwb import NWBFile\n'), ((56, 26, 57, 98), 'pynwb.ProcessingModule', 'ProcessingModule', (), '', False, 'from pynwb import ProcessingModule\n'), ((62, 8, 62, 85), 'nwbwidgets.base.processing_module', 'processing_module', ({(62, 26, 62, 56): "nwbfile.processing['behavior']", (62, 58, 62, 84): 'default_neurodata_vis_spec'}, {}), "(nwbfile.processing['behavior'], default_neurodata_vis_spec)", False, 'from nwbwidgets.base import show_neurodata_base, processing_module, nwb2widget, show_text_fields, fig2widget, vis2widget, show_fields, show_dynamic_table, df2accordion, lazy_show_over_data\n'), ((66, 8, 66, 61), 'nwbwidgets.base.nwb2widget', 'nwb2widget', ({(66, 19, 66, 32): 'self.position', (66, 34, 66, 60): 'default_neurodata_vis_spec'}, {}), '(self.position, default_neurodata_vis_spec)', False, 'from nwbwidgets.base import show_neurodata_base, processing_module, nwb2widget, show_text_fields, fig2widget, vis2widget, show_fields, show_dynamic_table, df2accordion, lazy_show_over_data\n'), ((75, 22, 75, 37), 'nwbwidgets.base.fig2widget', 'fig2widget', ({(75, 33, 75, 36): 'fig'}, {}), '(fig)', False, 'from nwbwidgets.base import show_neurodata_base, processing_module, nwb2widget, show_text_fields, fig2widget, vis2widget, show_fields, show_dynamic_table, df2accordion, lazy_show_over_data\n'), ((81, 13, 91, 31), 'ipywidgets.widgets.IntSlider', 'widgets.IntSlider', (), '', False, 'from ipywidgets import widgets\n'), ((97, 15, 97, 36), 'numpy.random.rand', 'np.random.rand', ({(97, 30, 97, 33): '160', (97, 34, 97, 35): '3'}, {}), '(160, 3)', True, 'import numpy as np\n'), ((99, 12, 99, 39), 'matplotlib.pyplot.figure', 'plt.figure', (), '', True, 'import matplotlib.pyplot as plt\n'), ((100, 8, 100, 22), 'matplotlib.pyplot.plot', 'plt.plot', ({(100, 17, 100, 21): 'data'}, {}), '(data)', True, 'import matplotlib.pyplot as plt\n'), ((105, 15, 105, 36), 'numpy.random.rand', 'np.random.rand', ({(105, 30, 105, 33): '160', (105, 34, 105, 35): '3'}, {}), '(160, 3)', True, 'import numpy as np\n'), ((124, 22, 124, 65), 'numpy.array', 'np.array', ({(124, 31, 124, 64): '[[1, 2, 3], [4, 5, 6], [7, 8, 9]]'}, {}), '([[1, 2, 3], [4, 5, 6], [7, 8, 9]])', True, 'import numpy as np\n'), ((127, 12, 127, 39), 'matplotlib.pyplot.figure', 'plt.figure', (), '', True, 'import matplotlib.pyplot as plt\n'), ((128, 8, 128, 22), 'matplotlib.pyplot.plot', 'plt.plot', ({(128, 17, 128, 21): 'data'}, {}), '(data)', True, 'import matplotlib.pyplot as plt\n'), ((134, 22, 134, 35), 'numpy.array', 'np.array', ({(134, 31, 134, 34): '[1]'}, {}), '([1])', True, 'import numpy as np\n'), ((137, 12, 137, 39), 'matplotlib.pyplot.figure', 'plt.figure', (), '', True, 'import matplotlib.pyplot as plt\n'), ((138, 8, 138, 22), 'matplotlib.pyplot.plot', 'plt.plot', ({(138, 17, 138, 21): 'data'}, {}), '(data)', True, 'import matplotlib.pyplot as plt\n'), ((146, 12, 146, 39), 'matplotlib.pyplot.figure', 'plt.figure', (), '', True, 'import matplotlib.pyplot as plt\n'), ((147, 8, 147, 22), 'matplotlib.pyplot.plot', 'plt.plot', ({(147, 17, 147, 21): 'data'}, {}), '(data)', True, 'import matplotlib.pyplot as plt\n'), ((149, 22, 149, 69), 'nwbwidgets.base.lazy_show_over_data', 'lazy_show_over_data', (), '', False, 'from nwbwidgets.base import show_neurodata_base, processing_module, nwb2widget, show_text_fields, fig2widget, vis2widget, show_fields, show_dynamic_table, df2accordion, lazy_show_over_data\n'), ((21, 49, 21, 58), 'dateutil.tz.tzlocal', 'tzlocal', ({}, {}), '()', False, 'from dateutil.tz import tzlocal\n'), ((22, 51, 22, 60), 'dateutil.tz.tzlocal', 'tzlocal', ({}, {}), '()', False, 'from dateutil.tz import tzlocal\n'), ((93, 26, 93, 40), 'nwbwidgets.base.vis2widget', 'vis2widget', ({(93, 37, 93, 39): 'wg'}, {}), '(wg)', False, 'from nwbwidgets.base import show_neurodata_base, processing_module, nwb2widget, show_text_fields, fig2widget, vis2widget, show_fields, show_dynamic_table, df2accordion, lazy_show_over_data\n'), ((102, 26, 102, 41), 'nwbwidgets.base.vis2widget', 'vis2widget', ({(102, 37, 102, 40): 'fig'}, {}), '(fig)', False, 'from nwbwidgets.base import show_neurodata_base, processing_module, nwb2widget, show_text_fields, fig2widget, vis2widget, show_fields, show_dynamic_table, df2accordion, lazy_show_over_data\n'), ((106, 13, 106, 68), 'pytest.raises', 'pytest.raises', (), '', False, 'import pytest\n'), ((107, 12, 107, 28), 'nwbwidgets.base.vis2widget', 'vis2widget', ({(107, 23, 107, 27): 'data'}, {}), '(data)', False, 'from nwbwidgets.base import show_neurodata_base, processing_module, nwb2widget, show_text_fields, fig2widget, vis2widget, show_fields, show_dynamic_table, df2accordion, lazy_show_over_data\n'), ((117, 40, 117, 60), 'pandas.DataFrame', 'pd.DataFrame', (), '', True, 'import pandas as pd\n'), ((44, 40, 44, 61), 'numpy.linspace', 'np.linspace', ({(44, 52, 44, 53): '0', (44, 55, 44, 56): '1', (44, 58, 44, 60): '20'}, {}), '(0, 1, 20)', True, 'import numpy as np\n'), ((51, 54, 51, 63), 'dateutil.tz.tzlocal', 'tzlocal', ({}, {}), '()', False, 'from dateutil.tz import tzlocal\n')]