import pytest

from savcfg.read import ConfigService, VariableNotFound, VarsReader


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

    def add_var(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 | None:
        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)


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

    def should_return_final_var_from_first_reader(self, service, second_reader):
        second_reader.add_var("one.var", "value")

        assert service.get("one.var") == "value"

    def should_return_dict_from_second_reader(self, service, second_reader):
        second_reader.add_var("a-var.level", "val-1")
        second_reader.add_var("a-var.level-1.level-2", "val-2")

        assert service.get_group("a-var") == {
            "level": "val-1",
            "level-1": {"level-2": "val-2"},
        }

    def should_return_first_reader_and_second_reader_merged(
        self, service, first_reader, second_reader
    ):
        second_reader.add_var("a-var.level0", "var")
        second_reader.add_var("a-var.level-1.level", "var-lev")
        second_reader.add_var("a-var.level-1.level-2", "val-second")
        first_reader.add_var("a-var.level-1.level-2", "val-first")

        assert service.get_group("a-var") == {
            "level0": "var",
            "level-1": {"level": "var-lev", "level-2": "val-first"},
        }

    def should_merge_with_app_variables(self, service, second_reader):
        second_reader.add_var("infra.username", "default-user")
        second_reader.add_var("infra.url", "infra-url")
        second_reader.add_var("app.infra.username", "app-user")

        assert service.get_group("infra") == {
            "username": "app-user",
            "url": "infra-url",
        }

    def should_raise_error_if_no_devel(self, first_reader, second_reader):
        service = ConfigService("app", first_reader, second_reader)

        with pytest.raises(VariableNotFound):
            service.get("no_devel")

    def should_return_first_reader_variable(self, service, first_reader, second_reader):
        first_reader.add_var("var.var", "val")
        second_reader.add_var("var.var", "val2")

        assert service.get("var.var") == "val"

    def should_return_second_reader_variable(self, service, second_reader):
        second_reader.add_var("a.var", "val2")

        assert service.get("a.var") == "val2"
