"""NumPy adapter tests for CrystFlux value system.

NOTE: The NumPy adapter is currently experimental. Technical notes and development
observations are temporarily documented in this file for reference during the
testing and refinement phase.

This module tests the bidirectional conversion between CrystFlux immutable values
and NumPy arrays, enabling seamless integration between CrystFlux's data
management capabilities and NumPy's numerical computing ecosystem.

Key Capabilities:
- Convert CrystFlux values (lists, dicts, scalars, None) to NumPy arrays
- Transform NumPy arrays back to CrystFlux values with mode selection
- Handle mixed-type data with automatic object dtype detection
- Performance caching for repeated conversions
- Safe conversion methods with graceful error handling

Supported Use Cases:
- Data science workflows with NumPy analysis
- Machine learning pipeline integration
- API data processing with statistical operations
- Multi-dimensional data handling
- International text processing (Unicode support)

Performance Features:
- LRU cache (128 entries) for conversion optimization
- Large array optimization (>10K elements)
- Memory-efficient dtype handling
"""

from typing import Any

import pytest
import numpy as np  # type: ignore

from crystflux.v1 import Crystallizer, StrictValue, LatentValue, DreamValue, VOID
from crystflux.v1.adapters import enable_dream_mode
from crystflux.v1.boundary import ModeNotSupportedError
from crystflux.v1.adapters import numpy as adapter


"""
=== NumPy Adapter Usage Examples ===

# Basic Conversion
value = Crystallizer.strict([1, 2, 3, 4, 5])
array = adapter.NumPyAdapter.to_numpy(value)  # → np.array([1, 2, 3, 4, 5])

# Mixed Type Handling
mixed = Crystallizer.strict([1, None, "text", True])
array = adapter.NumPyAdapter.to_numpy(mixed)  # → object dtype array

# Safe Conversion with Error Handling
array = adapter.NumPyAdapter.to_numpy_safe(value)  # Returns None for VOID
result = adapter.NumPyAdapter.from_numpy_safe(array)  # Returns VOID for errors

# Mode Selection for Different Reliability Requirements
strict_result = adapter.NumPyAdapter.from_numpy(array, mode="strict")    # Fail-fast
latent_result = adapter.NumPyAdapter.from_numpy(array, mode="latent")    # VOID fallback
dream_result = adapter.NumPyAdapter.from_numpy(array, mode="dream")      # Hallucination-tolerant

# Performance Optimization
adapter.NumPyAdapter.clear_cache()  # Clean cache for benchmarks
stats = adapter.NumPyAdapter.get_cache_stats()  # Monitor cache usage

# Machine Learning Pipeline Integration
training_data = Crystallizer.strict({
    "features": [[1.2, 3.4, 5.6], [7.8, 9.1, 2.3], [4.5, 6.7, 8.9]],
    "labels": [0, 1, 0],
    "metadata": {"model_version": "v1.0", "timestamp": "2024-01-01"}
})

# Extract features for ML training
features_array = adapter.NumPyAdapter.to_numpy(training_data.get("features"))
labels_array = adapter.NumPyAdapter.to_numpy(training_data.get("labels"))

# NumPy/ML operations (example with sklearn if available)
# from sklearn.preprocessing import StandardScaler
# scaler = StandardScaler()
# normalized_features = scaler.fit_transform(features_array)

# Convert processed data back to CrystFlux
processed_data = adapter.NumPyAdapter.from_numpy(features_array, mode="latent")
processed_labels = adapter.NumPyAdapter.from_numpy(labels_array, mode="strict")

# Batch Processing for Large Datasets
batch_data = Crystallizer.strict([range(1000) for _ in range(10)])  # 10 batches
for i, batch in enumerate(batch_data):
    batch_array = adapter.NumPyAdapter.to_numpy(batch)
    processed_batch = np.fft.fft(batch_array)  # Signal processing
    # Store results back in CrystFlux format
    result = adapter.NumPyAdapter.from_numpy(processed_batch, mode="dream")

# Time Series Forecasting Example
ts_data = Crystallizer.strict({
    "sequence": [1.0, 1.2, 0.9, 1.5, 1.8, 1.3, 1.7],
    "window_size": 3
})
sequence_array = adapter.NumPyAdapter.to_numpy(ts_data.get("sequence"))
# Create sliding windows for time series ML
windows = np.lib.stride_tricks.sliding_window_view(sequence_array, 3)

# Anomaly Detection Example
sensor_data = Crystallizer.strict([22.1, 22.3, 45.0, 22.5, 22.2])  # 45.0 is anomaly
sensor_array = adapter.NumPyAdapter.to_numpy(sensor_data)
z_scores = np.abs((sensor_array - np.mean(sensor_array)) / np.std(sensor_array))
anomalies = z_scores > 2.0

# Complete ML Training Pipeline Example
raw_data = Crystallizer.strict({
    "training_set": {
        "images": [[[0, 255], [128, 64]], [[32, 96], [160, 192]]],  # 2x2 images
        "labels": [0, 1],
        "metadata": {"dataset": "mnist_subset", "version": "1.0"}
    },
    "validation_set": {
        "images": [[[64, 128], [96, 32]]],
        "labels": [0],
        "metadata": {"split": "validation"}
    }
})

# Extract and preprocess training data
train_images = adapter.NumPyAdapter.to_numpy(raw_data.get("training_set").get("images"))
train_labels = adapter.NumPyAdapter.to_numpy(raw_data.get("training_set").get("labels"))

# Reshape for ML models (assuming 2x2 grayscale images)
train_images_reshaped = train_images.reshape(-1, 4)  # Flatten to 1D vectors

# Apply ML preprocessing (example with sklearn if available)
# from sklearn.decomposition import PCA
# pca = PCA(n_components=2)
# reduced_features = pca.fit_transform(train_images_reshaped)

# Store processed features back in CrystFlux
processed_features = adapter.NumPyAdapter.from_numpy(train_images_reshaped, mode="latent")
"""

"""
=== Future Enhancement Roadmap ===

Planned NumPy Adapter Enhancements:

1. Multi-dimensional Array Support
   - Current: 1D arrays only for dict values
   - Future: Full 2D/3D/ND array preservation
   - Use case: Matrix operations, tensor processing

2. Sparse Matrix Integration
   - Current: Dense arrays only
   - Future: scipy.sparse matrix support
   - Use case: Large-scale ML, recommendation systems

3. GPU Acceleration
   - Current: CPU-only NumPy arrays
   - Future: CuPy/PyTorch tensor conversion
   - Use case: Deep learning, high-performance computing

4. Streaming Data Support
   - Current: Batch conversion only
   - Future: Incremental/streaming conversion
   - Use case: Real-time data processing, IoT

5. Advanced Type Mapping
   - Current: Basic JSON types
   - Future: Pandas DataFrame, Polars integration
   - Use case: Data science workflows

6. Memory-Mapped Arrays
   - Current: In-memory arrays
   - Future: np.memmap support for large datasets
   - Use case: Big data processing, out-of-core computation

7. Custom Dtype Registry
   - Current: Auto-detection only
   - Future: User-defined type conversion rules
   - Use case: Domain-specific data types

8. Parallel Processing
   - Current: Single-threaded conversion
   - Future: Multi-threaded/multi-process conversion
   - Use case: Large dataset preprocessing
"""


@pytest.fixture
def sample_arrays() -> dict[str, np.ndarray]:
    """Sample NumPy arrays for testing."""
    return {
        "int_1d": np.array([1, 2, 3, 4, 5]),
        "float_1d": np.array([1.1, 2.2, 3.3, 4.4, 5.5]),
        "str_1d": np.array(["道可道", "非常道", "无名天地之始"]),
        "bool_1d": np.array([True, False, True, False]),
        "int_2d": np.array([[1, 2], [3, 4]]),
        "large_array": np.arange(15000),  # > 10K elements for performance testing
        "empty_array": np.array([]),
        "scalar": np.array(42),
    }


@pytest.fixture(autouse=True)
def clear_cache_before_each_test():
    """Clear cache before each test to ensure test isolation."""
    adapter.NumPyAdapter.clear_cache()


class TestBasicConversion:
    """Test basic NumPy conversion functionality."""

    def test_to_numpy_with_string_list(self, tao_data: dict[str, Any]) -> None:
        """Test converting string list to NumPy array."""
        works = Crystallizer.strict(tao_data["laozi"]["works"])
        array = adapter.NumPyAdapter.to_numpy(works)

        assert isinstance(array, np.ndarray)
        assert array.dtype == object
        assert len(array) == 1
        assert array[0] == "道徳経"

    def test_to_numpy_with_authors_list(self, tao_data: dict[str, Any]) -> None:
        """Test converting authors list to NumPy array."""
        authors = Crystallizer.strict(tao_data["anthology"]["authors"])
        array = adapter.NumPyAdapter.to_numpy(authors)

        assert isinstance(array, np.ndarray)
        assert array.dtype == object
        assert len(array) == 2
        assert array[0] == "老子"
        assert array[1] == "荘子"

    def test_to_numpy_with_dict_values(self, tao_data: dict[str, Any]) -> None:
        """Test converting dict values to NumPy array."""
        laozi = Crystallizer.strict(tao_data["laozi"])
        array = adapter.NumPyAdapter.to_numpy(laozi)

        assert isinstance(array, np.ndarray)
        assert array.dtype == object
        # Dict values should be converted to array
        expected_values = list(tao_data["laozi"].values())
        assert len(array) == len(expected_values)

    def test_to_numpy_with_scalar_value(self) -> None:
        """Test converting scalar value to NumPy array."""
        scalar = Crystallizer.strict(42)
        array = adapter.NumPyAdapter.to_numpy(scalar)

        assert isinstance(array, np.ndarray)
        assert len(array) == 1
        assert array[0] == 42

    def test_to_numpy_with_boolean(self) -> None:
        """Test converting boolean value to NumPy array."""
        boolean = Crystallizer.strict(True)
        array = adapter.NumPyAdapter.to_numpy(boolean)

        assert isinstance(array, np.ndarray)
        assert len(array) == 1
        assert array[0]

    def test_from_numpy_basic_arrays(self, sample_arrays: dict[str, np.ndarray]) -> None:
        """Test converting basic NumPy arrays to CrystFlux values."""
        # Test 1D integer array
        value = adapter.NumPyAdapter.from_numpy(sample_arrays["int_1d"], mode="strict")
        assert isinstance(value, StrictValue)
        # After freezing, lists become tuples
        result = value.as_json_value()
        assert result == [1, 2, 3, 4, 5] or result == (1, 2, 3, 4, 5)

        # Test 1D string array
        value = adapter.NumPyAdapter.from_numpy(sample_arrays["str_1d"], mode="strict")
        result = value.as_json_value()
        assert result == ["道可道", "非常道", "无名天地之始"] or result == (
            "道可道",
            "非常道",
            "无名天地之始",
        )

    def test_from_numpy_multidimensional_array(self, sample_arrays: dict[str, np.ndarray]) -> None:
        """Test converting 2D array to CrystFlux value."""
        value = adapter.NumPyAdapter.from_numpy(sample_arrays["int_2d"], mode="strict")
        expected = [[1, 2], [3, 4]]
        # After freezing, lists become tuples, so we need to handle both
        result = value.as_json_value()
        assert result == expected or result == tuple(tuple(row) for row in expected)

    def test_from_numpy_scalar_array(self, sample_arrays: dict[str, np.ndarray]) -> None:
        """Test converting scalar array to CrystFlux value."""
        value = adapter.NumPyAdapter.from_numpy(sample_arrays["scalar"], mode="strict")
        assert value.as_json_value() == 42

    def test_from_numpy_empty_array(self, sample_arrays: dict[str, np.ndarray]) -> None:
        """Test converting empty array to CrystFlux value."""
        value = adapter.NumPyAdapter.from_numpy(sample_arrays["empty_array"], mode="strict")
        # Empty arrays become empty tuples after freezing, so check for empty sequence
        result = value.as_json_value()
        assert isinstance(result, (list, tuple)) and len(result) == 0


class TestConversionModes:
    """Test different CrystFlux modes with NumPy conversion."""

    def test_from_numpy_strict_mode(self, sample_arrays: dict[str, np.ndarray]) -> None:
        """Test from_numpy with strict mode."""
        value = adapter.NumPyAdapter.from_numpy(sample_arrays["int_1d"], mode="strict")
        assert isinstance(value, StrictValue)

    def test_from_numpy_latent_mode(self, sample_arrays: dict[str, np.ndarray]) -> None:
        """Test from_numpy with latent mode."""
        value = adapter.NumPyAdapter.from_numpy(sample_arrays["int_1d"], mode="latent")
        assert isinstance(value, LatentValue)

    def test_from_numpy_dream_mode(self, sample_arrays: dict[str, np.ndarray]) -> None:
        """Test from_numpy with dream mode."""
        with enable_dream_mode():
            value = adapter.NumPyAdapter.from_numpy(sample_arrays["int_1d"], mode="dream")
        assert isinstance(value, DreamValue)

    def test_from_numpy_invalid_mode(self, sample_arrays: dict[str, np.ndarray]) -> None:
        """Test from_numpy with invalid mode raises ModeNotSupportedError."""
        with pytest.raises(ModeNotSupportedError, match="Unsupported mode: invalid"):
            adapter.NumPyAdapter.from_numpy(sample_arrays["int_1d"], mode="invalid")  # type:ignore


class TestRoundtripConversion:
    """Test roundtrip conversion between CrystFlux and NumPy."""

    def test_basic_roundtrip_integer_array(self) -> None:
        """Test roundtrip conversion with integer array."""
        original_data = [1, 2, 3, 4, 5]
        original = Crystallizer.strict(original_data)

        array = adapter.NumPyAdapter.to_numpy(original)
        back_to_value = adapter.NumPyAdapter.from_numpy(array, mode="strict")

        assert back_to_value.as_json_value() == original.as_json_value()

    def test_roundtrip_string_array(self, tao_data: dict[str, Any]) -> None:
        """Test roundtrip conversion with string array."""
        original_data = tao_data["anthology"]["topics"]
        original = Crystallizer.strict(original_data)

        array = adapter.NumPyAdapter.to_numpy(original)
        back_to_value = adapter.NumPyAdapter.from_numpy(array, mode="strict")

        assert back_to_value.as_json_value() == original.as_json_value()

    def test_roundtrip_multidimensional_array(self) -> None:
        """Test roundtrip conversion with 2D array."""
        original_data = [[1, 2], [3, 4]]
        original = Crystallizer.strict(original_data)

        array = adapter.NumPyAdapter.to_numpy(original)
        back_to_value = adapter.NumPyAdapter.from_numpy(array, mode="strict")

        assert back_to_value.as_json_value() == original.as_json_value()

    def test_roundtrip_with_different_modes(self, sample_arrays: dict[str, np.ndarray]) -> None:
        """Test roundtrip conversion with different modes."""
        array = sample_arrays["int_1d"]

        for mode in ("strict", "latent"):
            value = adapter.NumPyAdapter.from_numpy(array, mode=mode)
            back_as_array = adapter.NumPyAdapter.to_numpy(value)
            assert np.array_equal(back_as_array, array)

        with enable_dream_mode():
            value = adapter.NumPyAdapter.from_numpy(array, mode="dream")
            back_as_array = adapter.NumPyAdapter.to_numpy(value)
            assert np.array_equal(back_as_array, array)

    def test_numpy_to_crystflux_to_numpy_direct(self, sample_arrays: dict[str, np.ndarray]) -> None:
        """Test direct NumPy -> CrystFlux -> NumPy conversion."""
        original_array = sample_arrays["float_1d"]

        crystflux_value = adapter.NumPyAdapter.from_numpy(original_array, mode="strict")
        back_as_array = adapter.NumPyAdapter.to_numpy(crystflux_value)

        assert np.array_equal(back_as_array, original_array)


class TestErrorHandling:
    """Test error handling in NumPy adapter."""

    def test_to_numpy_with_none_value(self) -> None:
        """Test converting None value to NumPy array."""
        none_value = Crystallizer.strict(None)
        array = adapter.NumPyAdapter.to_numpy(none_value)

        assert isinstance(array, np.ndarray)
        assert len(array) == 1
        assert array.dtype == object
        assert array[0] is None

    def test_to_numpy_unsupported_type(self) -> None:
        """Test to_numpy raises TypeError for unsupported types."""
        from typing import Any

        class SetValue(StrictValue):
            def __post_init__(self) -> None:
                # Skip parent's __post_init__ to avoid set validation, directly set the value
                object.__setattr__(self, "_value", {1, 2, 3})
                # Use empty array for sorted to avoid validation errors
                from crystflux.v1.core.json_types import SortedJsonValue

                object.__setattr__(self, "_sorted", SortedJsonValue())

            def as_json_value(self) -> Any:
                return {1, 2, 3}  # set is unsupported by NumPy adapter

        # Pass dummy valid value to constructor, then override in __post_init__
        set_value = SetValue([])

        with pytest.raises(TypeError, match="Cannot convert set to NumPy array"):
            adapter.NumPyAdapter.to_numpy(set_value)

    def test_to_numpy_with_void(self) -> None:
        """Test to_numpy_safe with VOID returns None."""
        result = adapter.NumPyAdapter.to_numpy_safe(VOID)
        assert result is None

    def test_to_numpy_safe_with_dtype(self) -> None:
        """to_numpy_safe forwards dtype when value is not VOID."""
        strict = Crystallizer.strict([1, 2, 3])
        array = adapter.NumPyAdapter.to_numpy_safe(strict, dtype=float)
        assert array is not None
        assert array.dtype == float

    def test_roundtrip_none_value(self) -> None:
        """Test roundtrip conversion of None value."""
        # CrystFlux -> NumPy -> CrystFlux
        original = Crystallizer.strict(None)
        array = adapter.NumPyAdapter.to_numpy(original)
        back_to_crystflux = adapter.NumPyAdapter.from_numpy(array, mode="strict")

        # None becomes [None] when converted to array, then back to tuple
        result = back_to_crystflux.as_json_value()
        assert isinstance(result, tuple) and len(result) == 1 and result[0] is None

    def test_mixed_array_with_none(self) -> None:
        """Test array containing None values."""
        mixed_data = [1, None, "string", True]
        value = Crystallizer.strict(mixed_data)
        array = adapter.NumPyAdapter.to_numpy(value)

        assert isinstance(array, np.ndarray)
        assert array.dtype == object
        assert len(array) == 4
        assert array[0] == 1
        assert array[1] is None
        assert array[2] == "string"
        assert array[3] is True

    def test_from_numpy_safe_handles_object_array(self) -> None:
        """Object arrays with bare object() elements return VOID."""
        invalid_array = np.array([object()], dtype=object)
        result = adapter.NumPyAdapter.from_numpy_safe(invalid_array, mode="strict")
        assert result.is_void()

    def test_from_numpy_safe_catches_conversion_errors(self) -> None:
        """Conversion errors should fall back to VOID."""

        class BadArray(np.ndarray):  # type: ignore[misc]
            def tolist(self):  # pragma: no cover - constructed via view
                raise RuntimeError("boom")

        base = np.array([1, 2, 3])
        bad = base.view(BadArray)

        result = adapter.NumPyAdapter.from_numpy_safe(bad, mode="strict")
        assert result.is_void()

    def test_from_numpy_with_invalid_mode(self, sample_arrays: dict[str, np.ndarray]) -> None:
        """Test from_numpy with invalid mode."""
        with pytest.raises(ModeNotSupportedError, match="Unsupported mode: nonexistent"):
            adapter.NumPyAdapter.from_numpy(sample_arrays["int_1d"], mode="nonexistent")  # type:ignore

    def test_from_numpy_bool_scalar(self) -> None:
        """Test converting NumPy bool_ scalar to Python bool."""
        bool_array = np.array(True)
        value = adapter.NumPyAdapter.from_numpy(bool_array, mode="strict")

        result = value.as_json_value()
        assert isinstance(result, bool)
        assert result is True

        false_array = np.array(False)
        false_value = adapter.NumPyAdapter.from_numpy(false_array, mode="strict")
        assert isinstance(false_value.as_json_value(), bool)
        assert false_value.as_json_value() is False


class TestCacheFunctionality:
    """Test caching functionality in NumPy adapter."""

    def test_cache_stats_initially_empty(self) -> None:
        """Test cache stats are initially empty."""
        stats = adapter.NumPyAdapter.get_cache_stats()
        assert stats["size"] == 0
        assert stats["max_size"] == 128

    def test_cache_conversion_and_retrieval(self) -> None:
        """Test that conversions are cached and retrieved."""
        # Clear cache first
        adapter.NumPyAdapter.clear_cache()

        value = Crystallizer.strict([1, 2, 3, 4, 5])

        # First conversion should cache the result
        array1 = adapter.NumPyAdapter.to_numpy(value)
        stats_after_first = adapter.NumPyAdapter.get_cache_stats()
        assert stats_after_first["size"] == 1

        # Second conversion should use cache
        array2 = adapter.NumPyAdapter.to_numpy(value)
        stats_after_second = adapter.NumPyAdapter.get_cache_stats()
        assert stats_after_second["size"] == 1  # Same size, cache hit

        assert np.array_equal(array1, array2)

    def test_cache_clear(self) -> None:
        """Test cache clearing functionality."""
        # Add something to cache
        value = Crystallizer.strict([1, 2, 3])
        adapter.NumPyAdapter.to_numpy(value)

        # Verify cache has content
        stats_before = adapter.NumPyAdapter.get_cache_stats()
        assert stats_before["size"] > 0

        # Clear cache
        adapter.NumPyAdapter.clear_cache()

        # Verify cache is empty
        stats_after = adapter.NumPyAdapter.get_cache_stats()
        assert stats_after["size"] == 0

    def test_convenience_functions_cached(self) -> None:
        """Test that convenience functions use caching."""
        # Clear cache
        adapter.NumPyAdapter.clear_cache()

        value = Crystallizer.strict([1, 2, 3])

        # Use convenience function
        array1 = adapter.NumPyAdapter.to_numpy(value)
        array2 = adapter.NumPyAdapter.to_numpy(value)

        assert np.array_equal(array1, array2)


class TestPerformanceAndLargeData:
    """Test performance with large datasets."""

    def test_large_array_conversion(self, sample_arrays: dict[str, np.ndarray]) -> None:
        """Test conversion of large arrays (>10K elements)."""
        large_array = sample_arrays["large_array"]

        # Convert to CrystFlux and back
        value = adapter.NumPyAdapter.from_numpy(large_array, mode="strict")
        back_as_array = adapter.NumPyAdapter.to_numpy(value)

        assert np.array_equal(back_as_array, large_array)

    def test_large_array_optimization(self) -> None:
        """Test that large arrays use copy=False optimization."""
        # Create a large list
        large_list = list(range(15000))
        value = Crystallizer.strict(large_list)

        # This should use the large array optimization path
        array = adapter.NumPyAdapter.to_numpy(value)

        assert isinstance(array, np.ndarray)
        assert len(array) == 15000

    def test_cache_with_large_data(self) -> None:
        """Test cache behavior with large datasets."""
        adapter.NumPyAdapter.clear_cache()

        # Convert large array
        large_list = list(range(12000))
        value = Crystallizer.strict(large_list)
        array1 = adapter.NumPyAdapter.to_numpy(value)

        # Check cache stats
        stats = adapter.NumPyAdapter.get_cache_stats()
        assert stats["size"] == 1

        # Convert again (should hit cache)
        array2 = adapter.NumPyAdapter.to_numpy(value)
        assert np.array_equal(array1, array2)


class TestEdgeCases:
    """Test edge cases and special scenarios."""

    def test_empty_data_conversion(self) -> None:
        """Test conversion of empty data structures."""
        # Empty list
        empty_list = Crystallizer.strict([])
        array = adapter.NumPyAdapter.to_numpy(empty_list)
        assert len(array) == 0

        # Empty dict
        empty_dict = Crystallizer.strict({})
        array = adapter.NumPyAdapter.to_numpy(empty_dict)
        assert len(array) == 0

    def test_mixed_type_data(self) -> None:
        """Test conversion of mixed-type data."""
        mixed_data = [1, "string", True, 3.14]
        value = Crystallizer.strict(mixed_data)
        array = adapter.NumPyAdapter.to_numpy(value)

        assert isinstance(array, np.ndarray)
        assert array.dtype == object
        assert len(array) == 4

    def test_nested_structures(self, tao_data: dict[str, Any]) -> None:
        """Test conversion of nested structures from taoist data."""
        fragments = Crystallizer.strict(tao_data["anthology"]["fragments"])
        array = adapter.NumPyAdapter.to_numpy(fragments)

        assert isinstance(array, np.ndarray)
        assert array.dtype == object
        assert len(array) == 2

    def test_unicode_strings(self, tao_data: dict[str, Any]) -> None:
        """Test conversion of Unicode strings (Chinese characters)."""
        quotes = Crystallizer.strict(tao_data["laozi"]["quotes_en"])
        array = adapter.NumPyAdapter.to_numpy(quotes)

        assert isinstance(array, np.ndarray)
        assert array[0] == "The Dao that can be spoken is not the eternal Dao."

    def test_dtype_parameter(self) -> None:
        """Test dtype parameter in to_numpy conversion."""
        value = Crystallizer.strict([1, 2, 3, 4, 5])

        # Test with specific dtype
        array_float = adapter.NumPyAdapter.to_numpy(value, dtype=np.float64)
        assert array_float.dtype == np.float64

        array_int = adapter.NumPyAdapter.to_numpy(value, dtype=np.int32)
        assert array_int.dtype == np.int32
