import pytest
from typing import Any

from crystflux.v1 import VOID
from crystflux.v1.core.void_reason import VoidReason
from crystflux.v1.core.void_value import ReasonedVoid


# ===== Basic VOID functionality tests =====

def test_void_truthiness_and_state() -> None:
    assert VOID.is_void()
    assert not VOID.has_value()
    assert not VOID  # __bool__ is False


def test_void_accessors_and_navigation() -> None:
    assert VOID.get("anything") is VOID
    assert VOID.at(0) is VOID
    assert VOID.first_rest() == (VOID, VOID)
    assert VOID.rest_last() == (VOID, VOID)
    assert VOID["key"] is VOID
    assert VOID() is VOID
    assert VOID.as_str() is None
    assert VOID.as_int() is None
    assert VOID.as_float() is None
    assert VOID.as_bool() is None
    assert VOID.as_str_array() is None
    assert VOID.as_int_array() is None
    assert VOID.as_float_array() is None


def test_void_expected_methods_raise() -> None:
    with pytest.raises(TypeError):
        VOID.expected_str()
    with pytest.raises(TypeError):
        VOID.expected_int()
    with pytest.raises(TypeError):
        VOID.expected_float()
    with pytest.raises(TypeError):
        VOID.expected_bool()
    with pytest.raises(TypeError):
        VOID.expected_str_array()
    with pytest.raises(TypeError):
        VOID.expected_int_array()
    with pytest.raises(TypeError):
        VOID.expected_float_array()


def test_void_internal_helpers() -> None:
    # Test _spawn
    assert VOID._spawn(123) is VOID # type:ignore
    assert VOID._spawn({"a": 1}) is VOID # type:ignore

    # Test __getattr__
    assert VOID.some_non_existent_attribute is VOID
    assert VOID.another_attribute.yet_another is VOID # Chaining

    # Test to_array
    assert VOID.to_array() is VOID

    # Test _as_object
    assert VOID._as_object() is None # type:ignore

    # Test _as_array
    assert VOID._as_array() is None # type:ignore


def test_void_with_value_absorbs() -> None:
    assert VOID.with_value(1) is VOID
    reasoned = ReasonedVoid(VoidReason.MISSING_KEY)
    result = reasoned.with_value(1)
    assert result is reasoned
    assert result.void_reason() is VoidReason.MISSING_KEY


# ===== Coverage gap filler tests =====

def test_void_map_method() -> None:
    """Test VOID.map() method - originally missing from coverage."""
    result = VOID.map(lambda x: x)
    assert result is VOID
    
    # Type-safe version with explicit Any annotation
    def multiply_by_two(y: Any) -> Any:
        return y * 2

    result2 = VOID.map(multiply_by_two)
    assert result2 is VOID


def test_void_reasoning_and_kwargs() -> None:
    """Test VOID reasoning and kwargs methods - coverage gap fillers."""
    assert not VOID.is_void_reasoning_enabled()
    assert VOID.inherit_kwargs() == {}
    assert VOID._void() is VOID  # type: ignore[attr-defined]
