"""
MCP Tool Definition Tests — validates that all aura_core modules
auto-register and expose correct MCP tool schemas.

Tests validate:
- All 7 engines register when imported
- Each tool definition has name, description, schema
- Tool schemas are valid JSON Schema (from Pydantic model_json_schema)
- Registry is idempotent (importing twice doesn't duplicate)
- get_mcp_tool_definitions() returns complete tool inventory
"""
import pytest
from aura_core.module_contract import (
    get_mcp_tool_definitions,
    list_modules,
    get_module,
    get_module_spec,
    _MODULE_REGISTRY,
)

EXPECTED_MODULES = ["valuation", "validator", "theme", "blueprint", "orchestrator"]


def _ensure_all_imported():
    import aura_core.valuation.engine
    import aura_core.validator.engine
    import aura_core.theme.engine
    import aura_core.llm.engine
    import aura_core.context.engine
    import aura_core.blueprint.engine
    import aura_core.orchestrator.engine


class TestModuleRegistration:
    def test_all_expected_modules_registered(self):
        _ensure_all_imported()
        registered = {spec.name for spec in list_modules()}
        for name in EXPECTED_MODULES:
            assert name in registered, f"Module '{name}' not registered"

    def test_no_duplicate_registrations(self):
        _ensure_all_imported()
        _ensure_all_imported()
        names = [spec.name for spec in list_modules()]
        assert len(names) == len(set(names))

    def test_each_module_has_callable(self):
        _ensure_all_imported()
        for name in EXPECTED_MODULES:
            fn = get_module(name)
            assert fn is not None, f"Module '{name}' has no callable"
            assert callable(fn)


class TestMCPToolDefinitions:
    def test_returns_list_of_dicts(self):
        _ensure_all_imported()
        tools = get_mcp_tool_definitions()
        assert isinstance(tools, list)
        assert len(tools) >= len(EXPECTED_MODULES)

    def test_each_production_tool_has_name_and_description(self):
        _ensure_all_imported()
        tools = get_mcp_tool_definitions()
        prod_tools = [t for t in tools if t["name"] in EXPECTED_MODULES]
        assert len(prod_tools) == len(EXPECTED_MODULES)
        for tool in prod_tools:
            assert "name" in tool, f"Tool missing 'name': {tool}"
            assert "description" in tool, f"Tool missing 'description': {tool}"
            assert len(tool["name"]) > 0
            assert len(tool["description"]) > 10, f"Tool '{tool['name']}' description too short"

    def test_each_tool_has_schema_fields(self):
        _ensure_all_imported()
        tools = get_mcp_tool_definitions()
        for tool in tools:
            assert "inputSchema" in tool
            assert "outputSchema" in tool

    def test_tool_names_match_expected(self):
        _ensure_all_imported()
        tools = get_mcp_tool_definitions()
        tool_names = {t["name"] for t in tools}
        for name in EXPECTED_MODULES:
            assert name in tool_names, f"MCP tool '{name}' not found"


class TestModuleSpecs:
    def test_each_spec_has_version(self):
        _ensure_all_imported()
        for name in EXPECTED_MODULES:
            spec = get_module_spec(name)
            assert spec is not None
            assert spec.version, f"Module '{name}' missing version"

    def test_each_spec_has_description(self):
        _ensure_all_imported()
        for name in EXPECTED_MODULES:
            spec = get_module_spec(name)
            assert len(spec.description) > 10, f"Module '{name}' description too short"

    def test_valuation_spec_details(self):
        _ensure_all_imported()
        spec = get_module_spec("valuation")
        assert "valuation" in spec.description.lower() or "domain" in spec.description.lower()

    def test_blueprint_spec_details(self):
        _ensure_all_imported()
        spec = get_module_spec("blueprint")
        assert "blueprint" in spec.description.lower() or "section" in spec.description.lower()

    def test_orchestrator_spec_details(self):
        _ensure_all_imported()
        spec = get_module_spec("orchestrator")
        assert "pipeline" in spec.description.lower() or "orchestrat" in spec.description.lower()


class TestTypedInputSchemas:
    def test_all_production_tools_have_populated_input_schema(self):
        _ensure_all_imported()
        tools = get_mcp_tool_definitions()
        for tool in tools:
            if tool["name"] in EXPECTED_MODULES:
                schema = tool["inputSchema"]
                assert isinstance(schema, dict), f"Tool '{tool['name']}' inputSchema not dict"
                assert "properties" in schema, f"Tool '{tool['name']}' inputSchema has no properties"
                assert len(schema["properties"]) > 0, f"Tool '{tool['name']}' inputSchema properties empty"

    def test_valuation_input_schema_has_domain(self):
        _ensure_all_imported()
        spec = get_module_spec("valuation")
        props = spec.input_schema.get("properties", {})
        assert "domain" in props
        assert "analysis" in props

    def test_theme_input_schema_has_colors(self):
        _ensure_all_imported()
        spec = get_module_spec("theme")
        props = spec.input_schema.get("properties", {})
        assert "mood" in props
        assert "primary" in props
        assert "secondary" in props
        assert "accent" in props

    def test_blueprint_input_schema_has_depth(self):
        _ensure_all_imported()
        spec = get_module_spec("blueprint")
        props = spec.input_schema.get("properties", {})
        assert "depth" in props

    def test_orchestrator_input_schema_has_stages(self):
        _ensure_all_imported()
        spec = get_module_spec("orchestrator")
        props = spec.input_schema.get("properties", {})
        assert "domain" in props
        assert "stages" in props
        assert "depth" in props

    def test_validator_input_schema_has_target(self):
        _ensure_all_imported()
        spec = get_module_spec("validator")
        props = spec.input_schema.get("properties", {})
        assert "data" in props
        assert "target" in props
        assert "auto_repair" in props
