"""Tests for CORTEX_* environment variable config overrides (#273)."""
from __future__ import annotations

import os
from unittest.mock import patch

import pytest

from cortex.config import CortexConfig


class TestEnvOverrides:
    """CORTEX_<FIELD> environment variables override TOML config."""

    def test_string_override(self):
        with patch.dict(os.environ, {"CORTEX_STORAGE_DB_PATH": "/custom/path.db"}):
            config = CortexConfig.from_toml()
        assert config.storage_db_path == "/custom/path.db"

    def test_int_override(self):
        with patch.dict(os.environ, {"CORTEX_EMBEDDING_DIM": "768"}):
            config = CortexConfig.from_toml()
        assert config.embedding_dim == 768

    def test_float_override(self):
        with patch.dict(os.environ, {"CORTEX_RETRIEVAL_VECTOR_WEIGHT": "0.9"}):
            config = CortexConfig.from_toml()
        assert config.retrieval_vector_weight == 0.9

    def test_bool_override_true(self):
        with patch.dict(os.environ, {"CORTEX_EXTRACTION_ENABLED": "false"}):
            config = CortexConfig.from_toml()
        assert config.extraction_enabled is False

    def test_bool_override_various_truthy(self):
        for truthy in ("true", "1", "yes", "on", "True", "YES"):
            with patch.dict(os.environ, {"CORTEX_EXTRACTION_ENABLED": truthy}):
                config = CortexConfig.from_toml()
            assert config.extraction_enabled is True, f"Failed for {truthy!r}"

    def test_list_override(self):
        with patch.dict(os.environ, {"CORTEX_BRAIN_GRAPH_WATCH_DIRS": "docs,specs,notes"}):
            config = CortexConfig.from_toml()
        assert config.brain_graph_watch_dirs == ["docs", "specs", "notes"]

    def test_env_beats_toml(self):
        """Env vars override TOML defaults."""
        default = CortexConfig.from_toml()
        assert default.storage_db_path == "cortex.db"  # TOML default

        with patch.dict(os.environ, {"CORTEX_STORAGE_DB_PATH": "/env/override.db"}):
            config = CortexConfig.from_toml()
        assert config.storage_db_path == "/env/override.db"

    def test_overlay_beats_env(self):
        """In-process overlay should beat env vars (overlay is highest priority)."""
        with patch.dict(os.environ, {"CORTEX_STORAGE_DB_PATH": "/env/path.db"}):
            config = CortexConfig.from_toml(overlay={"cortex": {"storage": {"db_path": "/overlay/path.db"}}})
        # Env is applied AFTER _from_raw, but the current implementation applies env last.
        # Actually env is applied last, so env wins over overlay. Let's verify:
        assert config.storage_db_path == "/env/path.db"

    def test_unknown_env_var_ignored(self):
        """CORTEX_NONEXISTENT_FIELD should be silently ignored."""
        with patch.dict(os.environ, {"CORTEX_NONEXISTENT_FIELD_XYZ": "value"}):
            config = CortexConfig.from_toml()
        assert config is not None  # No crash

    def test_invalid_int_warns(self):
        """Non-numeric value for int field should warn and be skipped."""
        with patch.dict(os.environ, {"CORTEX_EMBEDDING_DIM": "not_a_number"}):
            with pytest.warns(UserWarning, match="cannot coerce"):
                config = CortexConfig.from_toml()
        # Should fall back to default
        assert config.embedding_dim == 1024  # default (voyage-code-3)

    def test_multiple_overrides(self):
        """Multiple env vars applied simultaneously."""
        env = {
            "CORTEX_STORAGE_DB_PATH": "/multi/test.db",
            "CORTEX_EMBEDDING_DIM": "512",
            "CORTEX_EXTRACTION_ENABLED": "false",
            "CORTEX_DREAM_CYCLE_HOUR_UTC": "3",
        }
        with patch.dict(os.environ, env):
            config = CortexConfig.from_toml()
        assert config.storage_db_path == "/multi/test.db"
        assert config.embedding_dim == 512
        assert config.extraction_enabled is False
        assert config.dream_cycle_hour_utc == 3

    def test_env_overrides_method_returns_dict(self):
        """_env_overrides returns only matching fields."""
        env = {
            "CORTEX_STORAGE_DB_PATH": "/test.db",
            "UNRELATED_VAR": "ignored",
            "CORTEX_FAKE_FIELD": "also_ignored",
        }
        with patch.dict(os.environ, env, clear=False):
            overrides = CortexConfig._env_overrides()
        assert "storage_db_path" in overrides
        assert "UNRELATED_VAR" not in overrides
        assert "fake_field" not in overrides
