"""Tests for data/formats.py — reverse conversion + edge cases."""

import pytest

from soup_cli.data.formats import (
    detect_format,
    format_to_messages,
    messages_to_format,
)

# --- detect_format edge cases ---

def test_detect_format_empty():
    """Empty dataset should raise ValueError."""
    with pytest.raises(ValueError, match="Empty"):
        detect_format([])


def test_detect_format_unknown_keys():
    """Unrecognized keys should raise ValueError."""
    with pytest.raises(ValueError, match="Cannot detect"):
        detect_format([{"foo": "bar", "baz": 123}])


# --- format_to_messages edge cases ---

def test_format_to_messages_unknown_format():
    """Unknown format should raise ValueError."""
    with pytest.raises(ValueError, match="Unknown format"):
        format_to_messages({"a": "b"}, "unknown_fmt")


def test_format_to_messages_bad_row():
    """Missing required keys should return None (gracefully handled)."""
    result = format_to_messages({"wrong": "keys"}, "alpaca")
    assert result is None


def test_convert_chatml_passthrough():
    """ChatML format should pass through messages directly."""
    row = {"messages": [{"role": "user", "content": "hi"}, {"role": "assistant", "content": "yo"}]}
    result = format_to_messages(row, "chatml")
    assert result["messages"] == row["messages"]


def test_convert_alpaca_with_system():
    """Alpaca row with system field should include system message."""
    row = {
        "instruction": "Translate",
        "input": "",
        "output": "Done",
        "system": "You are a translator.",
    }
    result = format_to_messages(row, "alpaca")
    assert len(result["messages"]) == 3
    assert result["messages"][0]["role"] == "system"
    assert result["messages"][0]["content"] == "You are a translator."


def test_convert_sharegpt_with_system():
    """ShareGPT with system turn should map correctly."""
    row = {
        "conversations": [
            {"from": "system", "value": "Be helpful."},
            {"from": "human", "value": "Hello"},
            {"from": "gpt", "value": "Hi there!"},
        ]
    }
    result = format_to_messages(row, "sharegpt")
    assert result["messages"][0]["role"] == "system"
    assert result["messages"][1]["role"] == "user"
    assert result["messages"][2]["role"] == "assistant"


# --- reverse conversion: messages_to_format ---

def test_messages_to_alpaca():
    """Convert messages back to alpaca format."""
    row = {
        "messages": [
            {"role": "user", "content": "What is Python?"},
            {"role": "assistant", "content": "A programming language."},
        ]
    }
    result = messages_to_format(row, "alpaca")
    assert result is not None
    assert result["instruction"] == "What is Python?"
    assert result["output"] == "A programming language."
    assert result["input"] == ""


def test_messages_to_alpaca_with_system():
    """Convert messages with system to alpaca format."""
    row = {
        "messages": [
            {"role": "system", "content": "Be brief."},
            {"role": "user", "content": "What is AI?"},
            {"role": "assistant", "content": "Artificial Intelligence."},
        ]
    }
    result = messages_to_format(row, "alpaca")
    assert result["system"] == "Be brief."
    assert result["instruction"] == "What is AI?"
    assert result["output"] == "Artificial Intelligence."


def test_messages_to_sharegpt():
    """Convert messages to sharegpt format."""
    row = {
        "messages": [
            {"role": "user", "content": "Hello"},
            {"role": "assistant", "content": "Hi!"},
        ]
    }
    result = messages_to_format(row, "sharegpt")
    assert result is not None
    convs = result["conversations"]
    assert len(convs) == 2
    assert convs[0]["from"] == "human"
    assert convs[0]["value"] == "Hello"
    assert convs[1]["from"] == "gpt"
    assert convs[1]["value"] == "Hi!"


def test_messages_to_chatml():
    """Convert to chatml should return the row as-is."""
    row = {
        "messages": [
            {"role": "user", "content": "Test"},
            {"role": "assistant", "content": "OK"},
        ]
    }
    result = messages_to_format(row, "chatml")
    assert result is row  # should be the same object (passthrough)


def test_messages_to_unknown_format():
    """Unknown target format should raise ValueError."""
    row = {"messages": [{"role": "user", "content": "hi"}]}
    with pytest.raises(ValueError, match="Cannot convert"):
        messages_to_format(row, "unknown")


def test_messages_to_format_bad_row():
    """Broken row should return None."""
    result = messages_to_format({"bad": "data"}, "alpaca")
    assert result is None


# --- round-trip tests ---

def test_roundtrip_alpaca():
    """alpaca → messages → alpaca should preserve data."""
    original = {"instruction": "Explain ML", "input": "", "output": "ML is..."}
    messages = format_to_messages(original, "alpaca")
    back = messages_to_format(messages, "alpaca")
    assert back["instruction"] == original["instruction"]
    assert back["output"] == original["output"]


def test_roundtrip_sharegpt():
    """sharegpt → messages → sharegpt should preserve data."""
    original = {
        "conversations": [
            {"from": "human", "value": "Hi"},
            {"from": "gpt", "value": "Hello!"},
        ]
    }
    messages = format_to_messages(original, "sharegpt")
    back = messages_to_format(messages, "sharegpt")
    assert back["conversations"][0]["from"] == "human"
    assert back["conversations"][0]["value"] == "Hi"
    assert back["conversations"][1]["from"] == "gpt"
    assert back["conversations"][1]["value"] == "Hello!"
