"""Regression tests for the egress-policy validators in settings_routes.

Covers validate_allowed_local_hostnames, which rejects public hostnames
from being whitelisted as "local". The validator was previously dead code:
it built its probe context via ``EgressContext.__new__`` + attribute
assignment, which raises ``FrozenInstanceError`` on the frozen dataclass
(and also set a non-existent ``allowed_local_hostnames`` field instead of
the real ``local_hostnames``). The guard therefore never ran — every save
that touched ``llm.allowed_local_hostnames`` either crashed or, if the
exception were swallowed, silently accepted public hostnames.

Source: src/local_deep_research/web/routes/settings_routes.py
"""

from local_deep_research.security.egress.validators import (
    validate_allowed_local_hostnames,
)

KEY = "llm.allowed_local_hostnames"


class TestValidateAllowedLocalHostnames:
    def test_missing_key_returns_none(self):
        """No hostnames in the payload => nothing to validate."""
        assert validate_allowed_local_hostnames({}, {}) is None

    def test_does_not_raise_frozeninstanceerror(self):
        """The core regression: building the probe context must not crash.

        Before the fix this raised dataclasses.FrozenInstanceError. The
        whole point is that the function returns a value (None or an error
        dict) rather than throwing.
        """
        # Should simply return (not raise) for any well-formed input.
        result = validate_allowed_local_hostnames({KEY: '["127.0.0.1"]'}, {})
        assert result is None or isinstance(result, dict)

    def test_local_hostnames_accepted(self):
        """Private/loopback addresses classify as local => accepted."""
        result = validate_allowed_local_hostnames(
            {KEY: '["192.168.1.50", "127.0.0.1", "10.0.0.1"]'}, {}
        )
        assert result is None

    def test_public_hostname_rejected(self):
        """A public IP must be rejected with an error dict naming the key."""
        result = validate_allowed_local_hostnames({KEY: '["8.8.8.8"]'}, {})
        assert isinstance(result, dict)
        assert result["key"] == KEY
        assert "PUBLIC" in result["error"]
        assert "8.8.8.8" in result["error"]

    def test_invalid_json_returns_error(self):
        result = validate_allowed_local_hostnames({KEY: "not-valid-json["}, {})
        assert isinstance(result, dict)
        assert result["key"] == KEY

    def test_non_list_value_returns_error(self):
        result = validate_allowed_local_hostnames({KEY: '"single"'}, {})
        assert isinstance(result, dict)
        assert "list" in result["error"].lower()

    def test_empty_and_whitespace_entries_skipped(self):
        """Blank entries are ignored, not classified — so a list of only
        blanks is accepted."""
        result = validate_allowed_local_hostnames(
            {KEY: '["", "   ", "127.0.0.1"]'}, {}
        )
        assert result is None

    def test_list_value_passed_directly(self):
        """The save pipeline may hand a Python list (already decoded)
        rather than a JSON string — both shapes must work."""
        result = validate_allowed_local_hostnames({KEY: ["192.168.1.1"]}, {})
        assert result is None
