import pytest

from crystflux.v1 import Crystallizer
from crystflux.v1.adapters import enable_dream_mode
from crystflux.v1.core.value_core import BaseValue
from crystflux.v1.core.value_modes import StrictValue


def test_to_array_fallback_spawn_for_custom_subclass() -> None:
    class CustomValue(StrictValue):
        pass

    custom = CustomValue([1, 2])
    result = custom.to_array()
    # Fallback branch returns _spawn(arr) for unknown subclasses
    assert isinstance(result, BaseValue)
    assert result.as_json_value() == (1, 2)


def test_expected_str_type_error_path() -> None:
    with pytest.raises(TypeError, match="Expected a string"):
        StrictValue(123).expected_str()


def test_expected_float_and_bool_paths() -> None:
    assert StrictValue(3.0).expected_float() == 3.0
    with pytest.raises(TypeError, match="Expected a float"):
        StrictValue("x").expected_float()

    assert StrictValue(True).expected_bool() is True
    with pytest.raises(TypeError, match="Expected a boolean"):
        StrictValue(0).expected_bool()


def test_basevalue_has_value_and_void_not_implemented() -> None:
    class BareValue(BaseValue):  # type: ignore[misc]
        pass

    bare = BareValue(1)  # type: ignore[abstract]
    assert bare.has_value() is True
    with pytest.raises(NotImplementedError):
        bare._void()  # type: ignore[attr-defined]


def test_is_void_returns_false_for_non_void_values() -> None:
    """Verify is_void() returns False for values that have data (value_core.py:230)."""
    strict = Crystallizer.strict({"a": 1})
    latent = Crystallizer.latent("hello")

    assert strict.is_void() is False
    assert latent.is_void() is False

    array_value = Crystallizer.latent([1, 2, 3])
    assert array_value.is_void() is False

    with enable_dream_mode():
        dream = Crystallizer.dream({"x": 42})
    assert dream.is_void() is False
