"""Tests for centralized argument coercion in call_tool."""

import jsonschema
import pytest
import respx
from httpx import Response

from platform_2step_mcp.server import TOOL_SCHEMAS, _coerce_arguments
from platform_2step_mcp.tools.analytics import handle_analytics_tool


# =============================================================================
# Unit tests for _coerce_arguments
# =============================================================================


class TestCoerceArguments:
    """Unit tests for _coerce_arguments."""

    def test_string_company_id_coerced_to_int(self):
        result = _coerce_arguments("query_analytics_db", {"company_id": "9479", "sql": "SELECT 1"})
        assert result["company_id"] == 9479
        assert isinstance(result["company_id"], int)

    def test_integer_company_id_unchanged(self):
        result = _coerce_arguments("query_analytics_db", {"company_id": 9479, "sql": "SELECT 1"})
        assert result["company_id"] == 9479
        assert isinstance(result["company_id"], int)

    def test_non_numeric_string_raises_validation_error(self):
        with pytest.raises(jsonschema.ValidationError, match="'abc' is not of type 'integer'"):
            _coerce_arguments("query_analytics_db", {"company_id": "abc", "sql": "SELECT 1"})

    def test_non_integer_fields_not_coerced(self):
        result = _coerce_arguments("query_analytics_db", {"company_id": 1, "sql": "123"})
        assert result["sql"] == "123"
        assert isinstance(result["sql"], str)

    def test_unknown_tool_returns_args_unchanged(self):
        args = {"company_id": "9479", "sql": "SELECT 1"}
        result = _coerce_arguments("nonexistent_tool", args)
        assert result == args

    def test_missing_key_in_arguments_not_affected(self):
        # Schema declares company_id but arguments doesn't have it — no error
        result = _coerce_arguments("query_analytics_db", {"sql": "SELECT 1"})
        assert result == {"sql": "SELECT 1"}

    def test_original_arguments_not_mutated(self):
        original = {"company_id": "9479", "sql": "SELECT 1"}
        result = _coerce_arguments("query_analytics_db", original)
        assert original["company_id"] == "9479"  # unchanged
        assert result["company_id"] == 9479


# =============================================================================
# Integration tests: coerce → validate → handler
# =============================================================================


class TestCoercionIntegration:
    """Integration tests for the coerce → validate pipeline."""

    @pytest.mark.asyncio
    async def test_query_with_string_company_id_succeeds(self, client, mock_api):
        mock_api.post("/api/v1/analytics/query").mock(
            return_value=Response(
                200,
                json={
                    "columns": ["name"],
                    "rows": [["Corte"]],
                    "row_count": 1,
                    "truncated": False,
                    "data_as_of": "2026-02-10T15:30:00Z",
                    "sync_lag_seconds": 60,
                    "snapshot_version": "v1",
                    "is_partial": False,
                },
            )
        )

        # Simulate what call_tool does: coerce, validate, call handler
        args = {"company_id": "1238", "sql": "SELECT name FROM services"}
        coerced = _coerce_arguments("query_analytics_db", args)

        schema = TOOL_SCHEMAS["query_analytics_db"]
        jsonschema.validate(instance=coerced, schema=schema)

        result = await handle_analytics_tool("query_analytics_db", coerced, client)
        assert len(result) == 1
        assert "Corte" in result[0].text

    @pytest.mark.asyncio
    async def test_status_with_string_company_id_succeeds(self, client, mock_api):
        mock_api.get("/api/v1/analytics/status/1238").mock(
            return_value=Response(
                200,
                json={
                    "company_id": 1238,
                    "state": "READY",
                    "snapshot_version": "v1",
                    "last_sync_at": "2026-02-10T15:30:00Z",
                    "sync_in_progress": False,
                    "tables_synced": ["bookings"],
                    "schema_version": 2,
                },
            )
        )

        args = {"company_id": "1238"}
        coerced = _coerce_arguments("get_analytics_status", args)

        schema = TOOL_SCHEMAS["get_analytics_status"]
        jsonschema.validate(instance=coerced, schema=schema)

        result = await handle_analytics_tool("get_analytics_status", coerced, client)
        assert len(result) == 1
        assert '"READY"' in result[0].text

    def test_non_numeric_company_id_fails_validation(self):
        with pytest.raises(jsonschema.ValidationError, match="'abc' is not of type 'integer'"):
            _coerce_arguments("query_analytics_db", {"company_id": "abc", "sql": "SELECT 1"})

    def test_coerced_args_pass_schema_validation(self):
        args = {"company_id": "9479", "sql": "SELECT 1"}
        coerced = _coerce_arguments("query_analytics_db", args)

        schema = TOOL_SCHEMAS["query_analytics_db"]
        # Should not raise
        jsonschema.validate(instance=coerced, schema=schema)
        assert coerced["company_id"] == 9479

    def test_uncoerced_string_fails_schema_validation(self):
        """Verifies the original bug: string company_id fails jsonschema validation."""
        args = {"company_id": "9479", "sql": "SELECT 1"}
        schema = TOOL_SCHEMAS["query_analytics_db"]

        with pytest.raises(jsonschema.ValidationError, match="is not of type 'integer'"):
            jsonschema.validate(instance=args, schema=schema)
