"""Tests for the DataPresentation class."""

from typing import Annotated, Literal

import holoviews as hv
import numpy as np
import param
import pytest

from holoviz_utils.dataviz import DataPresentation


def wave_callback(self, wave_type: Literal["sin", "cos", "tan"] = "sin",
                  frequency: Annotated[float, "[1,6]"] = 1.0,
                  amplitude: Annotated[float, "[3,9]"] = 3.0,
                  phase: Annotated[float, "[-3.14159,3.14159]"] = 0.0):
    """Simple test callback for testing DataPresentation."""
    x = np.linspace(0, 4 * np.pi, 1000)
    wave_func = getattr(np, wave_type)
    y = amplitude * wave_func(frequency * x + phase)
    return hv.Curve((x, y), kdims="x", vdims="y").opts(
        responsive=True, height=400, line_width=2, framewise=True
    )


def test_datapresentation_with_wave_callback():
    """Test initializing DataPresentation with the wave_callback function."""
    # Create a DataPresentation instance with wave_callback
    dp = DataPresentation(dm_funcs=[wave_callback])

    # Check that the instance was created
    assert dp is not None

    # Check that dm_funcs contains our function
    assert len(dp.dm_funcs) == 1
    assert dp.dm_funcs[0] == wave_callback

    # Check that widget_mapping was populated
    assert len(dp.widget_mapping) == 1

    # Check that parameters were created for the function arguments
    assert "wave_type" in dp.param
    assert "frequency" in dp.param
    assert "amplitude" in dp.param
    assert "phase" in dp.param

    # Check that a chart parameter was created
    assert "chart_000" in dp.param

    # Verify the chart is a DynamicMap
    chart = getattr(dp, "chart_000")
    assert isinstance(chart, hv.DynamicMap)

    # Check that the view was created
    assert dp.view is not None


def test_datapresentation_parameter_defaults():
    """Test that parameter defaults are correctly set."""
    dp = DataPresentation(dm_funcs=[wave_callback])

    # Check default values
    assert dp.wave_type == "sin"
    assert dp.frequency == 1.0
    assert dp.amplitude == 3.0
    assert dp.phase == 0.0


def test_datapresentation_parameter_bounds():
    """Test that parameter bounds are correctly set."""
    dp = DataPresentation(dm_funcs=[wave_callback])

    # Check that parameters have the correct bounds
    freq_param = dp.param.frequency
    assert hasattr(freq_param, "softbounds")
    assert freq_param.softbounds == (1.0, 6.0)

    amp_param = dp.param.amplitude
    assert hasattr(amp_param, "softbounds")
    assert amp_param.softbounds == (3.0, 9.0)

    phase_param = dp.param.phase
    assert hasattr(phase_param, "softbounds")
    # Check approximate values for pi
    assert phase_param.softbounds[0] == pytest.approx(-3.14159, rel=1e-4)
    assert phase_param.softbounds[1] == pytest.approx(3.14159, rel=1e-4)


def test_datapresentation_wave_type_parameter():
    """Test that wave_type parameter is correctly configured."""
    dp = DataPresentation(dm_funcs=[wave_callback])

    # Check that wave_type is a Selector parameter
    wave_type_param = dp.param.wave_type
    assert isinstance(wave_type_param, param.Selector)

    # Check that it has the correct options
    assert hasattr(wave_type_param, "objects")
    assert wave_type_param.objects == ["sin", "cos", "tan"]

    # Check default value
    assert dp.wave_type == "sin"


def test_datapresentation_empty():
    """Test initializing DataPresentation with no functions."""
    dp = DataPresentation()

    # Should initialize successfully even with no functions
    assert dp is not None
    assert len(dp.dm_funcs) == 0
    assert dp.view is not None
