"""
Regression test for issue #834: KeyError 'missing_vars' in CLI startup.

Verifies that:
1. check_tool_availability() returns dicts with 'env_vars' key
2. _show_tool_availability_warnings() handles the correct key names
3. No KeyError occurs when toolsets are unavailable
"""

import json
import sys
import os
from pathlib import Path
from unittest.mock import patch, MagicMock

import pytest

# Ensure project root on path
sys.path.insert(0, str(Path(__file__).parent.parent))

from tools.registry import registry


class TestCheckToolAvailabilityKeys:
    """Verify check_tool_availability returns the expected dict keys."""

    def test_unavailable_has_env_vars_key(self):
        """Unavailable toolsets must have 'env_vars', not 'missing_vars'."""
        available, unavailable = registry.check_tool_availability(quiet=True)

        for item in unavailable:
            assert "env_vars" in item, (
                f"Toolset '{item.get('name')}' missing 'env_vars' key. "
                f"Keys present: {list(item.keys())}"
            )
            assert "name" in item, f"Missing 'name' key in: {item}"
            assert "tools" in item, f"Missing 'tools' key in: {item}"
            # This was the bug: cli.py accessed 'missing_vars' which doesn't exist
            assert "missing_vars" not in item, (
                f"Toolset '{item.get('name')}' has legacy 'missing_vars' key — "
                f"should be 'env_vars'"
            )

    def test_unavailable_env_vars_is_list(self):
        """The 'env_vars' value should always be a list."""
        _, unavailable = registry.check_tool_availability(quiet=True)
        for item in unavailable:
            assert isinstance(item.get("env_vars"), list), (
                f"env_vars should be list, got {type(item.get('env_vars'))}"
            )

    def test_available_is_list_of_strings(self):
        """Available toolsets should be a list of toolset name strings."""
        available, _ = registry.check_tool_availability(quiet=True)
        assert isinstance(available, list)
        for ts in available:
            assert isinstance(ts, str), f"Toolset name should be string, got {type(ts)}"


class TestShowToolAvailabilityWarningsLogic:
    """Test the logic of _show_tool_availability_warnings without CLI overhead."""

    def test_filter_logic_with_env_vars(self):
        """The filter logic from cli.py should work with 'env_vars' key."""
        # Simulate what check_tool_availability returns
        unavailable = [
            {"name": "browser", "env_vars": ["BROWSERBASE_API_KEY"], "tools": ["browser_navigate"]},
            {"name": "web", "env_vars": ["FIRECRAWL_API_KEY"], "tools": ["web_search"]},
            {"name": "no_deps", "env_vars": [], "tools": ["some_tool"]},
        ]

        # This is the fixed logic from cli.py L3614
        api_key_missing = [u for u in unavailable if u.get("env_vars")]

        assert len(api_key_missing) == 2
        assert api_key_missing[0]["name"] == "browser"
        assert api_key_missing[1]["name"] == "web"

    def test_filter_logic_with_empty_env_vars(self):
        """Toolsets with empty env_vars should be filtered out."""
        unavailable = [
            {"name": "system_tool", "env_vars": [], "tools": ["terminal"]},
        ]
        api_key_missing = [u for u in unavailable if u.get("env_vars")]
        assert len(api_key_missing) == 0

    def test_display_logic_uses_env_vars(self):
        """The display loop should access 'env_vars', not 'missing_vars'."""
        item = {
            "name": "browser",
            "env_vars": ["BROWSERBASE_API_KEY", "BROWSER_PROJECT_ID"],
            "tools": ["browser_navigate", "browser_click", "browser_snapshot"],
        }

        # This is the fixed display logic from cli.py L3620-3623
        tools_str = ", ".join(item["tools"][:2])
        if len(item["tools"]) > 2:
            tools_str += f", +{len(item['tools'])-2} more"

        vars_str = ", ".join(item["env_vars"])

        assert tools_str == "browser_navigate, browser_click, +1 more"
        assert vars_str == "BROWSERBASE_API_KEY, BROWSER_PROJECT_ID"

    def test_old_key_would_crash(self):
        """Demonstrate that accessing 'missing_vars' would raise KeyError."""
        item = {"name": "test", "env_vars": ["KEY"], "tools": ["tool"]}
        with pytest.raises(KeyError):
            _ = item["missing_vars"]


class TestRegistryConsistency:
    """Verify registry internal consistency."""

    def test_all_toolsets_have_required_keys(self):
        """Every toolset snapshot should have name, env_vars, tools."""
        available, unavailable = registry.check_tool_availability(quiet=True)

        all_toolsets = available + [u["name"] for u in unavailable]
        assert len(all_toolsets) > 0, "No toolsets found at all"

        for item in unavailable:
            for key in ("name", "env_vars", "tools"):
                assert key in item, f"Missing '{key}' in unavailable toolset: {item}"

    def test_no_toolset_in_both_lists(self):
        """A toolset shouldn't appear in both available and unavailable."""
        available, unavailable = registry.check_tool_availability(quiet=True)
        unavailable_names = {u["name"] for u in unavailable}
        overlap = set(available) & unavailable_names
        assert len(overlap) == 0, f"Toolsets in both lists: {overlap}"


if __name__ == "__main__":
    pytest.main([__file__, "-v"])
