"""High-value tests for config/thread_settings.py pure logic."""

import unittest
from unittest.mock import MagicMock

from local_deep_research.config.thread_settings import (
    NoSettingsContextError,
    clear_settings_context,
    get_bool_setting_from_snapshot,
    get_setting_from_snapshot,
    get_settings_context,
    set_settings_context,
    settings_context,
    _thread_local,
)


class TestSettingsContextBasic(unittest.TestCase):
    def tearDown(self):
        clear_settings_context()

    def test_set_and_get_roundtrip(self):
        ctx = MagicMock()
        set_settings_context(ctx)
        assert get_settings_context() is ctx

    def test_clear_removes_context(self):
        set_settings_context(MagicMock())
        clear_settings_context()
        assert get_settings_context() is None

    def test_get_returns_none_when_not_set(self):
        clear_settings_context()
        assert get_settings_context() is None

    def test_clear_when_never_set(self):
        # Should not raise
        if hasattr(_thread_local, "settings_context"):
            del _thread_local.settings_context
        clear_settings_context()


class TestSettingsContextManager(unittest.TestCase):
    def tearDown(self):
        clear_settings_context()

    def test_sets_and_clears(self):
        ctx = MagicMock()
        with settings_context(ctx):
            assert get_settings_context() is ctx
        assert get_settings_context() is None

    def test_clears_on_exception(self):
        ctx = MagicMock()
        try:
            with settings_context(ctx):
                raise ValueError("test")
        except ValueError:
            pass
        assert get_settings_context() is None


class TestGetSettingFromSnapshot(unittest.TestCase):
    def tearDown(self):
        clear_settings_context()

    def test_key_in_snapshot_simple_value(self):
        snapshot = {"my_key": "my_value"}
        result = get_setting_from_snapshot("my_key", settings_snapshot=snapshot)
        assert result == "my_value"

    def test_key_in_snapshot_dict_with_value(self):
        snapshot = {"my_key": {"value": 42, "ui_element": "text"}}
        result = get_setting_from_snapshot("my_key", settings_snapshot=snapshot)
        # ui_element="text" maps to str converter, so result is "42"
        assert result == "42"

    def test_child_key_search(self):
        snapshot = {"parent.child1": "v1", "parent.child2": "v2"}
        result = get_setting_from_snapshot("parent", settings_snapshot=snapshot)
        assert isinstance(result, dict)
        assert result["child1"] == "v1"
        assert result["child2"] == "v2"

    def test_child_key_with_value_dict(self):
        snapshot = {"parent.child": {"value": "hello", "ui_element": "text"}}
        result = get_setting_from_snapshot("parent", settings_snapshot=snapshot)
        assert isinstance(result, dict)
        assert result["child"] == "hello"

    def test_fallback_to_thread_context(self):
        ctx = MagicMock()
        ctx.get_setting.return_value = "from_context"
        set_settings_context(ctx)
        result = get_setting_from_snapshot("some_key")
        assert result == "from_context"

    def test_thread_context_dict_with_value(self):
        ctx = MagicMock()
        ctx.get_setting.return_value = {"value": "extracted"}
        set_settings_context(ctx)
        result = get_setting_from_snapshot("some_key")
        assert result == "extracted"

    def test_default_returned_when_no_context(self):
        clear_settings_context()
        result = get_setting_from_snapshot("missing", default="fallback")
        assert result == "fallback"

    def test_raises_when_no_context_no_default(self):
        clear_settings_context()
        with self.assertRaises(NoSettingsContextError):
            get_setting_from_snapshot("missing")

    def test_snapshot_takes_priority_over_context(self):
        ctx = MagicMock()
        ctx.get_setting.return_value = "from_context"
        set_settings_context(ctx)
        snapshot = {"key": "from_snapshot"}
        result = get_setting_from_snapshot("key", settings_snapshot=snapshot)
        assert result == "from_snapshot"

    def test_none_value_in_snapshot_is_treated_as_found(self):
        # Regression for #4208: a key present in the snapshot with an
        # explicit None must be returned as None, not collapsed into
        # "not found" and replaced with the default. The previous
        # behavior broke the OpenAI embedding test path because
        # embeddings.openai.dimensions defaults to JSON null, then
        # raised NoSettingsContextError when no thread context was set.
        clear_settings_context()
        result = get_setting_from_snapshot(
            "key", default="default_val", settings_snapshot={"key": None}
        )
        assert result is None


class TestGetBoolSettingFromSnapshot(unittest.TestCase):
    def tearDown(self):
        clear_settings_context()

    def test_returns_true_from_string(self):
        snapshot = {"flag": "true"}
        result = get_bool_setting_from_snapshot(
            "flag", settings_snapshot=snapshot
        )
        assert result is True

    def test_returns_false_from_string(self):
        snapshot = {"flag": "false"}
        result = get_bool_setting_from_snapshot(
            "flag", settings_snapshot=snapshot
        )
        assert result is False

    def test_default_when_missing(self):
        result = get_bool_setting_from_snapshot(
            "missing", default=True, settings_snapshot={}
        )
        assert result is True

    def test_integer_one_is_true(self):
        snapshot = {"flag": 1}
        result = get_bool_setting_from_snapshot(
            "flag", settings_snapshot=snapshot
        )
        assert result is True


class TestGetSettingFromSnapshotExtra(unittest.TestCase):
    def tearDown(self):
        clear_settings_context()

    def test_basic_retrieval(self):
        snapshot = {"llm_key": "model_name"}
        result = get_setting_from_snapshot(
            "llm_key", settings_snapshot=snapshot
        )
        assert result == "model_name"


if __name__ == "__main__":
    unittest.main()
