"""Test typed argument parsing (k=v, k:=json, file, JSON string)."""

import json
import pytest
from mcpbundles.args import parse_tool_args, ArgParseError, _coerce_value


class TestParseToolArgs:
    def test_empty_args(self):
        assert parse_tool_args(()) == {}

    def test_key_value_string(self):
        result = parse_tool_args(("name=Alice",))
        assert result == {"name": "Alice"}

    def test_key_value_multiple(self):
        result = parse_tool_args(("name=Alice", "age=30", "active=true"))
        assert result == {"name": "Alice", "age": 30, "active": True}

    def test_key_value_with_equals_in_value(self):
        result = parse_tool_args(("query=a=b",))
        assert result == {"query": "a=b"}

    def test_json_typed_bool(self):
        result = parse_tool_args(("include_archived:=true",))
        assert result == {"include_archived": True}

    def test_json_typed_number(self):
        result = parse_tool_args(("limit:=10",))
        assert result == {"limit": 10}

    def test_json_typed_array(self):
        result = parse_tool_args(('tags:=["a","b"]',))
        assert result == {"tags": ["a", "b"]}

    def test_json_typed_object(self):
        result = parse_tool_args(('config:={"nested": true}',))
        assert result == {"config": {"nested": True}}

    def test_json_typed_invalid(self):
        with pytest.raises(ArgParseError, match="Invalid JSON"):
            parse_tool_args(("bad:={not json}",))

    def test_json_string_argument(self):
        result = parse_tool_args(('{"title": "Hello", "body": "World"}',))
        assert result == {"title": "Hello", "body": "World"}

    def test_json_string_invalid(self):
        with pytest.raises(ArgParseError, match="Invalid JSON argument"):
            parse_tool_args(("{broken json}",))

    def test_mixed_key_value_and_json_typed(self):
        result = parse_tool_args(("query=test", "limit:=10", "archived:=false"))
        assert result == {"query": "test", "limit": 10, "archived": False}

    def test_file_path(self, tmp_path):
        f = tmp_path / "args.json"
        f.write_text('{"key": "from_file"}')
        result = parse_tool_args((), file_path=str(f))
        assert result == {"key": "from_file"}

    def test_file_path_not_found(self):
        with pytest.raises(ArgParseError, match="File not found"):
            parse_tool_args((), file_path="/nonexistent/file.json")

    def test_file_path_invalid_json(self, tmp_path):
        f = tmp_path / "bad.json"
        f.write_text("not json")
        with pytest.raises(ArgParseError, match="Invalid JSON in"):
            parse_tool_args((), file_path=str(f))

    def test_bare_argument_raises(self):
        with pytest.raises(ArgParseError, match="Invalid argument"):
            parse_tool_args(("no_equals_sign",))


class TestCoerceValue:
    def test_true(self):
        assert _coerce_value("true") is True
        assert _coerce_value("True") is True
        assert _coerce_value("TRUE") is True

    def test_false(self):
        assert _coerce_value("false") is False

    def test_null(self):
        assert _coerce_value("null") is None

    def test_integer(self):
        assert _coerce_value("42") == 42
        assert _coerce_value("-1") == -1

    def test_float(self):
        assert _coerce_value("3.14") == 3.14

    def test_quoted_string_stays_string(self):
        assert _coerce_value('"42"') == "42"
        assert _coerce_value("'true'") == "true"

    def test_plain_string(self):
        assert _coerce_value("hello") == "hello"

    def test_empty_string(self):
        assert _coerce_value("") == ""
