"""Tests for TransformMixin."""
from __future__ import annotations

from typing import TYPE_CHECKING

import pytest

from ansiblelint.rules import TransformMixin

if TYPE_CHECKING:
    from collections.abc import MutableMapping, MutableSequence
    from typing import Any


DUMMY_MAP: dict[str, Any] = {
    "foo": "text",
    "bar": {"some": "text2"},
    "fruits": ["apple", "orange"],
    "answer": [{"forty-two": ["life", "universe", "everything"]}],
}
DUMMY_LIST: list[dict[str, Any]] = [
    {"foo": "text"},
    {"bar": {"some": "text2"}, "fruits": ["apple", "orange"]},
    {"answer": [{"forty-two": ["life", "universe", "everything"]}]},
]


@pytest.mark.parametrize(
    ("yaml_path", "data", "expected_error"),
    (
        ([0], DUMMY_MAP, KeyError),
        (["bar", 0], DUMMY_MAP, KeyError),
        (["fruits", 100], DUMMY_MAP, IndexError),
        (["answer", 1], DUMMY_MAP, IndexError),
        (["answer", 0, 42], DUMMY_MAP, KeyError),
        (["answer", 0, "42"], DUMMY_MAP, KeyError),
        ([100], DUMMY_LIST, IndexError),
        ([0, 0], DUMMY_LIST, KeyError),
        ([0, "wrong key"], DUMMY_LIST, KeyError),
        ([1, "bar", "wrong key"], DUMMY_LIST, KeyError),
        ([1, "fruits", "index should be int"], DUMMY_LIST, TypeError),
        ([1, "fruits", 100], DUMMY_LIST, IndexError),
    ),
)
def test_seek_with_bad_path(
    yaml_path: list[int | str],
    data: MutableMapping[str, Any] | MutableSequence[Any] | str,
    expected_error: type[Exception],
) -> None:
    """Verify that TransformMixin.seek() propagates errors."""
    with pytest.raises(expected_error):
        TransformMixin.seek(yaml_path, data)


@pytest.mark.parametrize(
    ("yaml_path", "data", "expected"),
    (
        pytest.param([], DUMMY_MAP, DUMMY_MAP, id="0"),
        pytest.param(["foo"], DUMMY_MAP, DUMMY_MAP["foo"], id="1"),
        pytest.param(["bar"], DUMMY_MAP, DUMMY_MAP["bar"], id="2"),
        pytest.param(["bar", "some"], DUMMY_MAP, DUMMY_MAP["bar"]["some"], id="3"),
        pytest.param(["fruits"], DUMMY_MAP, DUMMY_MAP["fruits"], id="4"),
        pytest.param(["fruits", 0], DUMMY_MAP, DUMMY_MAP["fruits"][0], id="5"),
        pytest.param(["fruits", 1], DUMMY_MAP, DUMMY_MAP["fruits"][1], id="6"),
        pytest.param(["answer"], DUMMY_MAP, DUMMY_MAP["answer"], id="7"),
        pytest.param(["answer", 0], DUMMY_MAP, DUMMY_MAP["answer"][0], id="8"),
        pytest.param(
            ["answer", 0, "forty-two"],
            DUMMY_MAP,
            DUMMY_MAP["answer"][0]["forty-two"],
            id="9",
        ),
        pytest.param(
            ["answer", 0, "forty-two", 0],
            DUMMY_MAP,
            DUMMY_MAP["answer"][0]["forty-two"][0],
            id="10",
        ),
        pytest.param(
            ["answer", 0, "forty-two", 1],
            DUMMY_MAP,
            DUMMY_MAP["answer"][0]["forty-two"][1],
            id="11",
        ),
        pytest.param(
            ["answer", 0, "forty-two", 2],
            DUMMY_MAP,
            DUMMY_MAP["answer"][0]["forty-two"][2],
            id="12",
        ),
        pytest.param([], DUMMY_LIST, DUMMY_LIST, id="13"),
        pytest.param([0], DUMMY_LIST, DUMMY_LIST[0], id="14"),
        pytest.param([0, "foo"], DUMMY_LIST, DUMMY_LIST[0]["foo"], id="15"),
        pytest.param([1], DUMMY_LIST, DUMMY_LIST[1], id="16"),
        pytest.param([1, "bar"], DUMMY_LIST, DUMMY_LIST[1]["bar"], id="17"),
        pytest.param(
            [1, "bar", "some"],
            DUMMY_LIST,
            DUMMY_LIST[1]["bar"]["some"],
            id="18",
        ),
        pytest.param([1, "fruits"], DUMMY_LIST, DUMMY_LIST[1]["fruits"], id="19"),
        pytest.param([1, "fruits", 0], DUMMY_LIST, DUMMY_LIST[1]["fruits"][0], id="20"),
        pytest.param([1, "fruits", 1], DUMMY_LIST, DUMMY_LIST[1]["fruits"][1], id="21"),
        pytest.param([2], DUMMY_LIST, DUMMY_LIST[2], id="22"),
        pytest.param([2, "answer"], DUMMY_LIST, DUMMY_LIST[2]["answer"], id="23"),
        pytest.param([2, "answer", 0], DUMMY_LIST, DUMMY_LIST[2]["answer"][0], id="24"),
        pytest.param(
            [2, "answer", 0, "forty-two"],
            DUMMY_LIST,
            DUMMY_LIST[2]["answer"][0]["forty-two"],
            id="25",
        ),
        pytest.param(
            [2, "answer", 0, "forty-two", 0],
            DUMMY_LIST,
            DUMMY_LIST[2]["answer"][0]["forty-two"][0],
            id="26",
        ),
        pytest.param(
            [2, "answer", 0, "forty-two", 1],
            DUMMY_LIST,
            DUMMY_LIST[2]["answer"][0]["forty-two"][1],
            id="27",
        ),
        pytest.param(
            [2, "answer", 0, "forty-two", 2],
            DUMMY_LIST,
            DUMMY_LIST[2]["answer"][0]["forty-two"][2],
            id="28",
        ),
        pytest.param(
            [],
            "this is a string that should be returned as is, ignoring path.",
            "this is a string that should be returned as is, ignoring path.",
            id="29",
        ),
        pytest.param(
            [2, "answer", 0, "forty-two", 2],
            "this is a string that should be returned as is, ignoring path.",
            "this is a string that should be returned as is, ignoring path.",
            id="30",
        ),
    ),
)
def test_seek(
    yaml_path: list[int | str],
    data: MutableMapping[str, Any] | MutableSequence[Any] | str,
    expected: Any,
) -> None:
    """Ensure TransformMixin.seek() retrieves the correct data."""
    actual = TransformMixin.seek(yaml_path, data)
    assert actual == expected
