"""Tests for the analyzer module."""

from mcp_diet.analyzer import (
    analyze_tool,
    analyze_tools,
    count_tokens,
    grade_tokens,
    schema_depth,
    tool_to_text,
)
from tests.fixtures.sample_tools import (
    ALL_TOOLS,
    BLOATED_TOOL,
    DEEPLY_NESTED_TOOL,
    MINIMAL_TOOL,
    SIMPLE_TOOL,
)


class TestCountTokens:
    def test_empty_string(self):
        assert count_tokens("") == 0

    def test_simple_string(self):
        tokens = count_tokens("hello world")
        assert tokens > 0

    def test_deterministic(self):
        text = "The quick brown fox"
        assert count_tokens(text) == count_tokens(text)


class TestSchemaDepth:
    def test_none_schema(self):
        assert schema_depth(None) == 0

    def test_empty_schema(self):
        assert schema_depth({}) == 0

    def test_flat_schema(self):
        schema = {
            "type": "object",
            "properties": {
                "name": {"type": "string"},
            },
        }
        assert schema_depth(schema) == 1

    def test_nested_schema(self):
        assert schema_depth(DEEPLY_NESTED_TOOL.inputSchema) == 5

    def test_array_items(self):
        schema = {
            "type": "object",
            "properties": {
                "items": {
                    "type": "array",
                    "items": {
                        "type": "object",
                        "properties": {
                            "name": {"type": "string"}
                        },
                    },
                }
            },
        }
        assert schema_depth(schema) == 3


class TestGradeTokens:
    def test_grade_a(self):
        assert grade_tokens(50) == "A"
        assert grade_tokens(199) == "A"

    def test_grade_b(self):
        assert grade_tokens(200) == "B"
        assert grade_tokens(499) == "B"

    def test_grade_c(self):
        assert grade_tokens(500) == "C"
        assert grade_tokens(999) == "C"

    def test_grade_d(self):
        assert grade_tokens(1000) == "D"
        assert grade_tokens(1999) == "D"

    def test_grade_f(self):
        assert grade_tokens(2000) == "F"
        assert grade_tokens(5000) == "F"


class TestToolToText:
    def test_includes_name(self):
        text = tool_to_text(SIMPLE_TOOL)
        assert "get_time" in text

    def test_includes_description(self):
        text = tool_to_text(SIMPLE_TOOL)
        assert "Get the current time" in text

    def test_includes_schema(self):
        text = tool_to_text(SIMPLE_TOOL)
        assert "timezone" in text


class TestAnalyzeTool:
    def test_minimal_tool_grade_a(self):
        result = analyze_tool(MINIMAL_TOOL)
        assert result.grade == "A"
        assert result.tokens > 0
        assert result.budget_pct > 0

    def test_simple_tool(self):
        result = analyze_tool(SIMPLE_TOOL)
        assert result.name == "get_time"
        assert result.tokens > 0
        assert result.desc_length == len("Get the current time")

    def test_bloated_tool_low_grade(self):
        result = analyze_tool(BLOATED_TOOL)
        assert result.grade in ("C", "D", "F")
        assert result.tokens > 500

    def test_deeply_nested_depth(self):
        result = analyze_tool(DEEPLY_NESTED_TOOL)
        assert result.schema_depth == 5

    def test_custom_budget(self):
        result = analyze_tool(SIMPLE_TOOL, budget=1000)
        assert result.budget_pct > analyze_tool(SIMPLE_TOOL, budget=200_000).budget_pct


class TestAnalyzeTools:
    def test_summary(self):
        summary = analyze_tools(ALL_TOOLS)
        assert summary.total_tokens > 0
        assert len(summary.tools) == len(ALL_TOOLS)
        assert len(summary.top_offenders) == 3
        assert summary.budget == 200_000
        assert summary.cost_per_1000 > 0

    def test_top_offenders_sorted(self):
        summary = analyze_tools(ALL_TOOLS)
        tokens = [t.tokens for t in summary.top_offenders]
        assert tokens == sorted(tokens, reverse=True)

    def test_budget_pct(self):
        summary = analyze_tools(ALL_TOOLS)
        assert summary.budget_pct == (summary.total_tokens / summary.budget) * 100
