from packaging.version import Version
from unittest import SkipTest

import numpy as np
import pandas as pd
import hvplot.pandas  # noqa
import pytest

from hvplot import hvPlotTabular
from hvplot.tests.util import makeDataFrame

try:
    import polars as pl
    import hvplot.polars  # noqa

    skip_polar = False
except ImportError:

    class pl:
        DataFrame = None
        LazyFrame = None
        Series = None

    skip_polar = True

try:
    import dask.dataframe as dd
    import hvplot.dask  # noqa
except ImportError:
    dd = None


TYPES = {t for t in dir(hvPlotTabular) if not t.startswith('_') and t != 'explorer'}
FRAME_TYPES = TYPES - {'bivariate', 'heatmap', 'hexbin', 'labels', 'vectorfield'}
SERIES_TYPES = FRAME_TYPES - {'points', 'polygons', 'ohlc', 'paths'}
frame_kinds = pytest.mark.parametrize('kind', sorted(FRAME_TYPES))
series_kinds = pytest.mark.parametrize('kind', sorted(SERIES_TYPES))

y_combinations = pytest.mark.parametrize(
    'y',
    (
        ['A', 'B', 'C', 'D'],
        ('A', 'B', 'C', 'D'),
        {'A', 'B', 'C', 'D'},
        np.array(['A', 'B', 'C', 'D']),
        pd.Index(['A', 'B', 'C', 'D']),
        pd.Series(['A', 'B', 'C', 'D']),
    ),
    ids=lambda x: type(x).__name__,
)


@frame_kinds
@y_combinations
def test_dataframe_pandas(kind, y):
    df = makeDataFrame()
    df.hvplot(y=y, kind=kind)


@series_kinds
def test_series_pandas(kind):
    ser = pd.Series(np.random.rand(10), name='A')
    ser.hvplot(kind=kind)


@pytest.mark.skipif(dd is None, reason='dask not installed')
@frame_kinds
@y_combinations
def test_dataframe_dask(kind, y):
    df = dd.from_pandas(makeDataFrame(), npartitions=2)
    assert isinstance(df, dd.DataFrame)
    df.hvplot(y=y, kind=kind)


@pytest.mark.skipif(dd is None, reason='dask not installed')
@series_kinds
def test_series_dask(kind):
    ser = dd.from_pandas(pd.Series(np.random.rand(10), name='A'), npartitions=2)
    assert isinstance(ser, dd.Series)
    ser.hvplot(kind=kind)


@pytest.mark.skipif(skip_polar, reason='polars not installed')
@pytest.mark.parametrize('cast', (pl.DataFrame, pl.LazyFrame))
@frame_kinds
@y_combinations
def test_dataframe_polars(kind, y, cast):
    df = cast(makeDataFrame())
    assert isinstance(df, cast)
    df.hvplot(y=y, kind=kind)


@pytest.mark.skipif(skip_polar, reason='polars not installed')
@series_kinds
def test_series_polars(kind):
    ser = pl.Series(values=np.random.rand(10), name='A')
    assert isinstance(ser, pl.Series)
    ser.hvplot(kind=kind)


@pytest.mark.skipif(skip_polar, reason='polars not installed')
@series_kinds
def test_series_polars_downstream(kind):
    if Version(pl.__version__) < Version('0.20.3'):
        raise SkipTest('plot namespace in Polars introduced in 0.20.3')
    ser = pl.Series(values=np.random.rand(10), name='A')
    assert isinstance(ser, pl.Series)
    ser.plot(kind=kind)
