"""Unit tests for the dynojson get_property function."""

import json

import pytest

from dynojson import get_property


class TestGetProperty:
    """Tests for JSON property extraction with dot-path and wildcard."""

    def test_simple_nested_path(self):
        result = json.loads(get_property('{"a":{"b":"c"}}', "a"))
        assert result == {"b": "c"}

    def test_deep_nested_path(self):
        result = get_property('{"a":{"b":"c"}}', "a.b")
        assert json.loads(result) == "c"

    def test_numeric_key(self):
        result = get_property('{"1":{"b":"c"}}', "1.b")
        assert json.loads(result) == "c"

    def test_array_index(self):
        result = json.loads(get_property('[{"a":{"b":{"c":"d"}}}]', "0.a.b"))
        assert result == {"c": "d"}

    def test_wildcard_maps_through_array(self):
        subject = json.dumps([
            {"a": 1, "b": {"c": 1}},
            {"a": 2, "b": {"c": 2}},
            {"a": 3, "b": {"d": 3}},
            {"a": 4},
        ])
        result = json.loads(get_property(subject, "*.b"))
        assert result == [{"c": 1}, {"c": 2}, {"d": 3}]

        result = json.loads(get_property(subject, "*.b.c"))
        assert result == [1, 2]

    def test_wildcard_nested_in_object(self):
        subject = json.dumps({
            "a": [
                {"c": {"d": 1}},
                {"c": {"d": 2}},
                {"c": {"d": 3}},
            ]
        })
        result = json.loads(get_property(subject, "a.*.c"))
        assert result == [{"d": 1}, {"d": 2}, {"d": 3}]

    def test_index_then_wildcard(self):
        subject = json.dumps([
            {"a": [10, 20, {"c": {"d": 3}}]},
            {"a": [11, 21, {"c": {"d": 4}}]},
            {"a": [12, 22, {"c": {"d": 5}}]},
            {"a": [12, 22, {}]},
        ])
        result = json.loads(get_property(subject, "2.a.*"))
        assert result == [12, 22, {"c": {"d": 5}}]

    def test_index_and_wildcard_deep(self):
        subject = json.dumps({
            "a": [
                {"c": {"d": [{"e": 1}, {"e": 2}, {"f": 3}]}},
                {"c": {"d": [{"e": 4}, {"g": 5}, {"e": 6}]}},
            ]
        })
        result = json.loads(get_property(subject, "a.1.c.d.*.e"))
        assert result == [4, 6]

    # ── Error cases ─────────────────────────────────────────────────────

    def test_empty_path_raises(self):
        with pytest.raises(ValueError, match="empty"):
            get_property("{}", "")

    def test_too_many_wildcards_raises(self):
        with pytest.raises(ValueError, match="asterisk"):
            get_property("{}", "a.*.b.*")

    def test_non_object_subject_raises(self):
        with pytest.raises(ValueError, match="non-object"):
            get_property('"string"', "a.b")

    def test_property_not_found_raises(self):
        with pytest.raises(ValueError, match="not found"):
            get_property('{"a":{"c":"b"}}', "a.c.b")

    def test_invalid_json_raises(self):
        with pytest.raises(ValueError):
            get_property("not json", "a")
