"""Coverage tests for settings/base.py targeting ~9 missing statements.

Uncovered functions/branches:
- ISettingsManager abstract methods (get_setting, set_setting, etc.)
- Verifying ABC contract prevents instantiation
- Partial subclass instantiation failures
- Keyword argument usage for all methods
"""

from abc import ABC
from typing import Any, Dict

import pytest

from local_deep_research.settings.base import ISettingsManager

MODULE = "local_deep_research.settings.base"


class ConcreteSettingsManager(ISettingsManager):
    """Minimal concrete implementation for testing ABC contract."""

    def __init__(self):
        self._store: Dict[str, Any] = {}

    def get_setting(self, key, default=None, check_env=True):
        return self._store.get(key, default)

    def set_setting(self, key, value, commit=True):
        self._store[key] = value
        return True

    def get_all_settings(self):
        return dict(self._store)

    def create_or_update_setting(self, setting, commit=True):
        if isinstance(setting, dict):
            self._store[setting.get("key", "")] = setting.get("value")
        return setting

    def delete_setting(self, key, commit=True):
        if key in self._store:
            del self._store[key]
            return True
        return False

    def get_bool_setting(self, key, default=False, check_env=True):
        return bool(self._store.get(key, default))

    def get_settings_snapshot(self):
        return dict(self._store)

    def load_from_defaults_file(self, commit=True, **kwargs):
        pass

    def import_settings(
        self, settings_data, commit=True, overwrite=True, delete_extra=False
    ):
        for k, v in settings_data.items():
            if overwrite or k not in self._store:
                self._store[k] = v


class TestISettingsManagerABC:
    """Tests for the abstract base class contract."""

    def test_cannot_instantiate_abc_directly(self):
        """ISettingsManager cannot be instantiated without implementing all methods."""
        with pytest.raises(TypeError):
            ISettingsManager()

    def test_is_abc_subclass(self):
        """ISettingsManager inherits from ABC."""
        assert issubclass(ISettingsManager, ABC)

    def test_has_nine_abstract_methods(self):
        """All 9 public methods are declared abstract."""
        expected = {
            "get_setting",
            "set_setting",
            "get_all_settings",
            "create_or_update_setting",
            "delete_setting",
            "get_bool_setting",
            "get_settings_snapshot",
            "load_from_defaults_file",
            "import_settings",
        }
        assert expected <= ISettingsManager.__abstractmethods__

    def test_concrete_implementation_instantiates(self):
        """Concrete implementation can be instantiated."""
        mgr = ConcreteSettingsManager()
        assert isinstance(mgr, ISettingsManager)

    def test_get_setting_returns_default(self):
        """get_setting returns default when key not found."""
        mgr = ConcreteSettingsManager()
        assert mgr.get_setting("missing", "fallback") == "fallback"

    def test_set_and_get_roundtrip(self):
        """set_setting and get_setting are consistent."""
        mgr = ConcreteSettingsManager()
        mgr.set_setting("mykey", "myval")
        assert mgr.get_setting("mykey") == "myval"

    def test_set_setting_returns_true(self):
        """set_setting returns True on success."""
        mgr = ConcreteSettingsManager()
        assert mgr.set_setting("k", "v") is True

    def test_get_all_settings_returns_dict(self):
        """get_all_settings returns empty dict."""
        mgr = ConcreteSettingsManager()
        assert mgr.get_all_settings() == {}

    def test_delete_setting_returns_true_when_present(self):
        """delete_setting returns True when key exists."""
        mgr = ConcreteSettingsManager()
        mgr.set_setting("k", "v")
        assert mgr.delete_setting("k") is True

    def test_delete_setting_returns_false_when_missing(self):
        """delete_setting returns False when key is absent."""
        mgr = ConcreteSettingsManager()
        assert mgr.delete_setting("no_such_key") is False

    def test_get_bool_setting_returns_default(self):
        """get_bool_setting returns default."""
        mgr = ConcreteSettingsManager()
        assert mgr.get_bool_setting("missing", True) is True

    def test_get_settings_snapshot_returns_dict(self):
        """get_settings_snapshot returns a dict snapshot."""
        mgr = ConcreteSettingsManager()
        mgr.set_setting("snap_key", "snap_val")
        snap = mgr.get_settings_snapshot()
        assert isinstance(snap, dict)
        assert snap.get("snap_key") == "snap_val"

    def test_import_settings_populates_store(self):
        """import_settings adds keys to the store."""
        mgr = ConcreteSettingsManager()
        mgr.import_settings({"key": "val", "num": 42})
        assert mgr.get_setting("key") == "val"
        assert mgr.get_setting("num") == 42

    def test_load_from_defaults_file_does_not_raise(self):
        """load_from_defaults_file runs without error."""
        mgr = ConcreteSettingsManager()
        mgr.load_from_defaults_file(commit=False)

    def test_missing_single_method_raises_on_instantiation(self):
        """A subclass missing one abstract method cannot be instantiated."""

        class Incomplete(ISettingsManager):
            def get_setting(self, key, default=None, check_env=True):
                return default

            def set_setting(self, key, value, commit=True):
                return True

            def get_all_settings(self):
                return {}

            def create_or_update_setting(self, setting, commit=True):
                return None

            def delete_setting(self, key, commit=True):
                return False

            def get_bool_setting(self, key, default=False, check_env=True):
                return default

            def get_settings_snapshot(self):
                return {}

            def load_from_defaults_file(self, commit=True, **kwargs):
                pass

            # import_settings intentionally omitted

        with pytest.raises(TypeError):
            Incomplete()
