"""Tests for DreamValue mode behavior."""

from typing import Any

import pytest

from crystflux.v1 import Crystallizer, DreamValue, VOID
from crystflux.v1.adapters import enable_dream_mode
from crystflux.v1.core.value_array import DreamArrayValue
from crystflux.v1.core.void_reason import VoidReason


def test_dream_undefined_methods_collapse_to_void(tao_data: dict[str, Any]) -> None:
    """Test that undefined methods collapse to void in dream mode."""
    dream = DreamValue(tao_data["laozi"])
    result = dream.missing_api()  # type: ignore[attr-defined]
    assert result.is_void()
    assert not result
    assert dream.get("works").at(99).is_void()


def test_dream_void_value_short_circuits_get_and_at() -> None:
    """Test that dream void value short circuits get and at operations."""
    dream_void = DreamValue(VOID.as_json_value())
    assert dream_void.is_void()
    assert dream_void.get("anything") is dream_void
    assert dream_void.at(0) is dream_void


def test_dream_void_reasoning_and_desire_logging() -> None:
    """Test dream void reasoning and desire logging."""
    events: list[tuple[str, Any, tuple[str, ...]]] = []
    dream = DreamValue(
        {"x": 1}, on_desire=lambda m, r, c: events.append((m, r, c)), _void_reasoning_enabled=True
    )

    void_result = dream.missing_method()  # type: ignore[attr-defined]
    assert void_result.is_void()
    assert void_result._void_reason == VoidReason.DESIRE_CALL  # type: ignore[attr-defined]
    assert events == [("missing_method", dream.as_json_value(), ("missing_method",))]

    missing_key = dream.get("missing")
    assert missing_key.is_void()
    assert missing_key._void_reason == VoidReason.MISSING_KEY  # type: ignore[attr-defined]


def test_dream_inherit_kwargs_and_spawn_void() -> None:
    """Test dream inherit kwargs and spawn void."""
    dream = DreamValue(
        {"a": 1},
        chain_steps=("a",),
        _void_reason=VoidReason.TYPE_MISMATCH,
        _void_reasoning_enabled=True,
    )
    kwargs = dream.inherit_kwargs()
    assert kwargs["chain_steps"] == ("a",)
    assert kwargs["_void_reason"] == VoidReason.TYPE_MISMATCH
    assert kwargs["_void_reasoning_enabled"] is True

    spawned = dream.spawn_void(("a", "b"), reason=VoidReason.MISSING_KEY)
    assert spawned.chain_steps == ("a", "b")
    assert spawned._void_reason == VoidReason.MISSING_KEY  # type: ignore[attr-defined]

    assert dream.has_value() is True
    assert dream.spawn_void(("x",)).has_value() is False


def test_dream_dunder_access_raises_attribute_error() -> None:
    """Test that dream dunder access raises attribute error."""
    dream = DreamValue({"x": 1})
    with pytest.raises(AttributeError):
        getattr(dream, "__missing__")


def test_dream_array_first_rest_and_rest_last() -> None:
    """Test dream array first_rest and rest_last operations."""
    dream_array = DreamValue([1, 2, 3])
    first, rest = dream_array.first_rest()
    assert first.as_int() == 1
    assert rest.as_json_value() == (2, 3)

    rest_part, last = dream_array.rest_last()
    assert rest_part.as_json_value() == (1, 2)
    assert last.as_int() == 3


def test_map_filter_modes_and_dream_void_chaining(tao_data: dict[str, Any]) -> None:
    """Test map and filter operations for dream mode."""
    fragments = tao_data["anthology"]["fragments"]

    with enable_dream_mode():
        dream_fragments = Crystallizer.dream(fragments)
        dream_sources = dream_fragments.map(lambda v: v.get("source"))
        assert dream_sources.as_json_value() == tuple(f["source"] for f in fragments)

        dream_missing_chain = (
            Crystallizer.dream({"a": 1}).missing().get("missing").map(lambda v: v.get("x"))  # type:ignore
        )
        assert dream_missing_chain.is_void()
        assert dream_missing_chain.filter(lambda v: True).is_void()  # type:ignore


def test_as_float_array_and_expected() -> None:
    """Test as_float_array and expected_float_array for dream mode."""
    dream = DreamValue([1.1, True, 2.2])
    assert dream.as_float_array() == (1.1, 2.2)
    with pytest.raises(TypeError):
        dream.expected_float_array()


def test_as_scalars_collects_nested_scalars() -> None:
    """Test as_scalars for dream mode."""
    bool_and_int = DreamValue([True, 1])
    assert bool_and_int.as_scalars() == (True, 1)


def test_handle_non_array_split_modes() -> None:
    """Test that dream mode returns VOID for split operations on non-arrays."""
    dream_non_array = DreamValue({"key": "value"})
    assert dream_non_array.first_rest() == (VOID, VOID)
    assert dream_non_array.rest_last() == (VOID, VOID)


def test_array_operations_type_errors_and_void_fallbacks() -> None:
    """Test array operations with void fallbacks for dream mode."""
    dream_non_array = DreamArrayValue({"key": "value"})

    dream_map_result = dream_non_array.map(lambda v: v)
    assert dream_map_result.is_void()

    dream_filter_result = dream_non_array.filter(lambda v: True)
    assert dream_filter_result.is_void()


def test_internal_array_helper_methods() -> None:
    """Test internal array helper methods for dream mode."""
    dream_non_array = DreamArrayValue({"key": "value"})

    dream_first_rest = dream_non_array.first_rest()
    assert dream_first_rest == (VOID, VOID)

    dream_rest_last = dream_non_array.rest_last()
    assert dream_rest_last == (VOID, VOID)
