"""Tests for field mapping utilities."""

import pytest
from toothfairyai.utils import to_camel_case, convert_kwargs_to_api
from toothfairyai.agents.field_mappings import AGENT_FIELD_MAPPINGS, AGENT_EXPLICIT_PARAMS
from toothfairyai.agent_functions.field_mappings import (
    AGENT_FUNCTION_FIELD_MAPPINGS,
    AGENT_FUNCTION_EXPLICIT_PARAMS,
)


class TestToCamelCase:
    """Tests for to_camel_case function."""

    def test_simple_snake_case(self):
        """Test simple snake_case conversion."""
        assert to_camel_case("json_output_structure") == "jsonOutputStructure"
        assert to_camel_case("enable_json_output") == "enableJsonOutput"
        assert to_camel_case("max_tokens") == "maxTokens"

    def test_single_word(self):
        """Test single word passes through unchanged."""
        assert to_camel_case("label") == "label"
        assert to_camel_case("description") == "description"
        assert to_camel_case("temperature") == "temperature"

    def test_already_camel_case(self):
        """Test already camelCase passes through unchanged."""
        assert to_camel_case("jsonOutputStructure") == "jsonOutputStructure"
        assert to_camel_case("enableJsonOutput") == "enableJsonOutput"

    def test_multiple_underscores(self):
        """Test multiple underscores."""
        assert to_camel_case("hand_off_to_original_agent_on_completion") == "handOffToOriginalAgentOnCompletion"

    def test_empty_string(self):
        """Test empty string."""
        assert to_camel_case("") == ""

    def test_trailing_underscore(self):
        """Test trailing underscore."""
        assert to_camel_case("test_") == "test"


class TestConvertKwargsToApi:
    """Tests for convert_kwargs_to_api function."""

    def test_standard_conversion(self):
        """Test standard snake_case → camelCase conversion."""
        kwargs = {"json_output_structure": {"type": "object"}}
        result = convert_kwargs_to_api(kwargs, {})
        assert result == {"jsonOutputStructure": {"type": "object"}}

    def test_exception_mapping(self):
        """Test exception mapping overrides standard conversion."""
        kwargs = {"has_ner": True}
        result = convert_kwargs_to_api(kwargs, AGENT_FIELD_MAPPINGS)
        assert result == {"hasNER": True}

    def test_workspace_id_mapping(self):
        """Test workspace_id → workspaceid (lowercase) mapping."""
        kwargs = {"workspace_id": "test-id"}
        result = convert_kwargs_to_api(kwargs, AGENT_FIELD_MAPPINGS)
        assert result == {"workspaceid": "test-id"}

    def test_explicit_params_skipped(self):
        """Test explicit params are skipped."""
        kwargs = {"label": "test", "description": "test desc", "json_output_structure": {}}
        result = convert_kwargs_to_api(kwargs, AGENT_FIELD_MAPPINGS, {"label", "description"})
        assert result == {"jsonOutputStructure": {}}

    def test_mixed_kwargs(self):
        """Test mixed snake_case and camelCase kwargs."""
        kwargs = {
            "json_output_structure": {},
            "enableJsonOutput": True,
            "has_ner": False,
        }
        result = convert_kwargs_to_api(kwargs, AGENT_FIELD_MAPPINGS)
        assert result == {
            "jsonOutputStructure": {},
            "enableJsonOutput": True,
            "hasNER": False,
        }

    def test_unknown_field_fallback(self):
        """Test unknown field uses standard camelCase fallback."""
        kwargs = {"unknown_field": "value"}
        result = convert_kwargs_to_api(kwargs, AGENT_FIELD_MAPPINGS)
        assert result == {"unknownField": "value"}

    def test_empty_kwargs(self):
        """Test empty kwargs."""
        result = convert_kwargs_to_api({}, AGENT_FIELD_MAPPINGS)
        assert result == {}


class TestAgentFieldMappings:
    """Tests for Agent field mappings."""

    def test_id_suffix_uppercase(self):
        """Test ID suffix mappings (uppercase)."""
        assert AGENT_FIELD_MAPPINGS["parent_agent_id"] == "parentAgentID"
        assert AGENT_FIELD_MAPPINGS["parent_chat_id"] == "parentChatID"
        assert AGENT_FIELD_MAPPINGS["cloned_agent_id"] == "clonedAgentID"

    def test_id_suffix_lowercase_exception(self):
        """Test lowercase Id exception."""
        assert AGENT_FIELD_MAPPINGS["sip_dispatch_rule_id"] == "sipDispatchRuleId"

    def test_uppercase_acronyms(self):
        """Test uppercase acronym mappings."""
        assert AGENT_FIELD_MAPPINGS["has_ner"] == "hasNER"
        assert AGENT_FIELD_MAPPINGS["agentic_rag"] == "agenticRAG"
        assert AGENT_FIELD_MAPPINGS["allow_external_api"] == "allowExternalAPI"
        assert AGENT_FIELD_MAPPINGS["is_mfa_enabled"] == "isMFAEnabled"

    def test_explicit_params_set(self):
        """Test explicit params set contains expected values."""
        assert "label" in AGENT_EXPLICIT_PARAMS
        assert "description" in AGENT_EXPLICIT_PARAMS
        assert "temperature" in AGENT_EXPLICIT_PARAMS
        assert "max_tokens" in AGENT_EXPLICIT_PARAMS
        assert "max_history" in AGENT_EXPLICIT_PARAMS
        assert "top_k" in AGENT_EXPLICIT_PARAMS
        assert "doc_top_k" in AGENT_EXPLICIT_PARAMS
        assert "charting" in AGENT_EXPLICIT_PARAMS


class TestAgentFunctionFieldMappings:
    """Tests for AgentFunction field mappings."""

    def test_id_suffix_uppercase(self):
        """Test ID suffix mappings (uppercase)."""
        assert AGENT_FUNCTION_FIELD_MAPPINGS["authorisation_id"] == "authorisationID"
        assert AGENT_FUNCTION_FIELD_MAPPINGS["code_execution_environment_id"] == "codeExecutionEnvironmentID"
        assert AGENT_FUNCTION_FIELD_MAPPINGS["db_connection_id"] == "dbConnectionID"
        assert AGENT_FUNCTION_FIELD_MAPPINGS["pre_execution_fn_id"] == "preExecutionFnID"

    def test_oauth_uppercase(self):
        """Test OAuth uppercase mapping."""
        assert AGENT_FUNCTION_FIELD_MAPPINGS["oauth_connection_id"] == "OAuthConnectionID"

    def test_mcp_uppercase(self):
        """Test MCP uppercase mapping."""
        assert AGENT_FUNCTION_FIELD_MAPPINGS["is_mcp_server"] == "isMCPServer"


class TestIntegration:
    """Integration tests for full conversion flow."""

    def test_agent_update_kwargs_full(self):
        """Test full agent update kwargs conversion."""
        kwargs = {
            "json_output_structure": {"type": "object"},
            "enable_json_output": True,
            "has_ner": True,
            "parent_agent_id": "agent-123",
            "llm_url": "https://api.example.com",
            "unknown_field": "value",
        }
        result = convert_kwargs_to_api(kwargs, AGENT_FIELD_MAPPINGS, AGENT_EXPLICIT_PARAMS)
        
        assert result["jsonOutputStructure"] == {"type": "object"}
        assert result["enableJsonOutput"] is True
        assert result["hasNER"] is True
        assert result["parentAgentID"] == "agent-123"
        assert result["llmUrl"] == "https://api.example.com"
        assert result["unknownField"] == "value"

    def test_agent_function_update_kwargs_full(self):
        """Test full agent function update kwargs conversion."""
        kwargs = {
            "name": "test_function",
            "request_type": "post",
            "authorisation_id": "auth-123",
            "is_mcp_server": True,
            "oauth_connection_id": "oauth-123",
            "custom_execution_code": "print('hello')",
        }
        result = convert_kwargs_to_api(kwargs, AGENT_FUNCTION_FIELD_MAPPINGS, AGENT_FUNCTION_EXPLICIT_PARAMS)
        
        assert result["name"] == "test_function"
        assert result["requestType"] == "post"
        assert result["authorisationID"] == "auth-123"
        assert result["isMCPServer"] is True
        assert result["OAuthConnectionID"] == "oauth-123"
        assert result["customExecutionCode"] == "print('hello')"

    def test_user_can_bypass_with_camelcase(self):
        """Test user can bypass conversion by using camelCase directly."""
        kwargs = {
            "jsonOutputStructure": {"type": "object"},
            "hasNER": True,
        }
        result = convert_kwargs_to_api(kwargs, AGENT_FIELD_MAPPINGS)
        
        assert result["jsonOutputStructure"] == {"type": "object"}
        assert result["hasNER"] is True