import pytest

from savcfg.read import ConfigService, VariableNotFound, VarsReader


class InMemVarsReader(VarsReader):
    def __init__(self):
        self._data = {}

    def add(self, key: str, value: str):
        self._data[key] = value

    def list_vars(self) -> list[str]:
        return list(self._data.keys())

    def read(self, key: str) -> str:
        return self._data.get(key, "")


@pytest.fixture
def first_reader():
    return InMemVarsReader()


@pytest.fixture
def second_reader():
    return InMemVarsReader()


@pytest.fixture
def service(first_reader, second_reader):
    return ConfigService("app", first_reader, second_reader)


_CASES = [
    {"var": '"string"', "name": "String", "value": "string"},
    {"var": "1", "name": "Integer", "value": 1},
    {"var": "1.2", "name": "Float", "value": 1.2},
    {"var": "null", "name": "None", "value": None},
    {"var": "true", "name": "Boolean", "value": True},
]


class A_ConfigService:
    def should_return_none_var(self, service):
        with pytest.raises(VariableNotFound):
            service.get_primitive("no-exist")

    def should_return_primitives_from_first_reader(self, service, first_reader):
        for c in _CASES:
            first_reader.add("varname", c["var"])
            assert (
                service.get_primitive("varname") == c["value"]
            ), f'Failed on case {c["name"]}'

    def should_return_primitive_first_from_app(self, service, first_reader):
        first_reader.add("app.varname", "1")
        first_reader.add("varname", "2")
        assert service.get_primitive("varname") == 1

    def should_return_primtive_first_from_first_reader(
        self, service, first_reader, second_reader
    ):
        first_reader.add("varname", "1")
        second_reader.add("varname", "2")
        assert service.get_primitive("varname") == 1

    def should_return_primitive_from_second_if_no_first(self, service, second_reader):
        second_reader.add("varname", "2")
        assert service.get_primitive("varname") == 2

    def should_return_group_from_first_reader(self, service, first_reader):
        first_reader.add("varname", '{"one": 1, "two": 2}')

        assert service.get_group("varname") == {"one": 1, "two": 2}

    def should_return_merge_group_from_first_reader_and_app(
        self, service, first_reader
    ):
        first_reader.add("varname", '{"one": 1, "two": 2}')
        first_reader.add("app.varname", '{"one": 0, "two": 2, "three": 3}')

        assert service.get_group("varname") == {"one": 0, "two": 2, "three": 3}

    def should_return_merge_group_from_first_reader_to_second_reader(
        self, service, first_reader, second_reader
    ):
        second_reader.add("varname", '{"one": 1, "two": 2}')
        first_reader.add("varname", '{"one": 0, "two": 2, "three": 3}')

        assert service.get_group("varname") == {"one": 0, "two": 2, "three": 3}
