"""Tests for Generate JSONL node."""

from unittest.mock import MagicMock

import pytest

from fw_nodes_core.nodes.generate_jsonl import GenerateJSONLNode


@pytest.fixture
def jsonl_context(node_execution_context):
    """Context with mock store_binary."""
    node_execution_context.store_binary = MagicMock(
        return_value={"_type": "storage_reference", "uri": "s3://bucket/output.jsonl"}
    )
    return node_execution_context


@pytest.mark.asyncio
async def test_basic_list(jsonl_context):
    """Test converting a list of dicts to JSONL."""
    node = GenerateJSONLNode()
    data = [{"name": "Alice"}, {"name": "Bob"}]

    result = await node.execute({"data": data}, jsonl_context)

    assert result.line_count == 2
    assert result.size_bytes > 0
    assert result.storage_ref["_type"] == "storage_reference"

    # Verify store_binary was called with correct JSONL content
    call_args = jsonl_context.store_binary.call_args
    stored_data = call_args[1]["data"] if "data" in call_args[1] else call_args[0][0]
    lines = stored_data.decode("utf-8").split("\n")
    assert len(lines) == 2
    assert '"Alice"' in lines[0]
    assert '"Bob"' in lines[1]


@pytest.mark.asyncio
async def test_empty_list(jsonl_context):
    """Test that empty list produces zero lines."""
    node = GenerateJSONLNode()

    result = await node.execute({"data": []}, jsonl_context)

    assert result.line_count == 0
    assert result.size_bytes == 0


@pytest.mark.asyncio
async def test_non_list_input_raises(jsonl_context):
    """Test that non-list input raises ValueError."""
    node = GenerateJSONLNode()

    with pytest.raises((ValueError, Exception)):
        await node.execute({"data": "not a list"}, jsonl_context)


@pytest.mark.asyncio
async def test_unicode_content(jsonl_context):
    """Test that unicode content is preserved."""
    node = GenerateJSONLNode()
    data = [{"text": "日本語"}, {"text": "émojis 🎉"}]

    result = await node.execute({"data": data}, jsonl_context)

    assert result.line_count == 2
    call_args = jsonl_context.store_binary.call_args
    stored_data = call_args[1]["data"] if "data" in call_args[1] else call_args[0][0]
    content = stored_data.decode("utf-8")
    assert "日本語" in content
    assert "🎉" in content


@pytest.mark.asyncio
async def test_unserializable_item_raises(jsonl_context):
    """Test that items that can't be serialized raise ValueError."""
    node = GenerateJSONLNode()

    with pytest.raises(ValueError, match="Failed to serialize"):
        await node.execute({"data": [{"bad": set([1, 2])}]}, jsonl_context)
