"""Tests for concise response mode in loom_ready and loom_status."""

from __future__ import annotations

import pytest

from loom.mcp.tools import _concise_task, _VERBOSE_FIELDS


# ---------------------------------------------------------------------------
# Sample task dict matching Task.model_dump(mode="json") output
# ---------------------------------------------------------------------------

def _make_task_dict(
    task_id: str = "loom-abcd1234",
    title: str = "Implement feature X",
    priority: str = "p0",
    status: str = "pending",
    assignee: str | None = None,
    context: dict | None = None,
    output: dict | None = None,
) -> dict:
    """Build a realistic full task dict for testing."""
    return {
        "id": task_id,
        "project_id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
        "title": title,
        "status": status,
        "priority": priority,
        "assignee": assignee,
        "parent_id": None,
        "context": context or {
            "description": "A long description of the feature...",
            "notes": "Implementation notes spanning many lines...",
            "testing": "Unit tests, integration tests, e2e tests...",
            "patterns": ["factory pattern", "observer pattern"],
            "edge_cases": ["null input", "concurrent access"],
            "complexity_reasoning": "This is a medium-complexity task...",
        },
        "output": output or {},
        "done_when": "All tests pass and PR is merged",
        "depends_on": ["loom-dep00001", "loom-dep00002"],
        "created_at": "2026-02-22T10:00:00+00:00",
        "updated_at": "2026-02-22T10:30:00+00:00",
        "claimed_at": None,
        "done_at": None,
        "claim_expires_at": None,
        "retry_count": 0,
        "max_retries": 3,
        "last_failed_at": None,
        "retry_after": None,
        "dead_letter": False,
        "dead_letter_reason": None,
    }


# ---------------------------------------------------------------------------
# _concise_task unit tests
# ---------------------------------------------------------------------------

class TestConciseTask:
    """Tests for the _concise_task helper."""

    def test_strips_verbose_fields(self):
        """Concise mode should remove all fields in _VERBOSE_FIELDS."""
        full = _make_task_dict()
        concise = _concise_task(full)
        for field in _VERBOSE_FIELDS:
            assert field not in concise, f"Field '{field}' should be stripped"

    def test_keeps_essential_fields(self):
        """Concise mode should preserve id, title, priority, status, assignee, depends_on."""
        full = _make_task_dict(assignee="agent-1")
        concise = _concise_task(full)
        assert concise["id"] == "loom-abcd1234"
        assert concise["title"] == "Implement feature X"
        assert concise["priority"] == "p0"
        assert concise["status"] == "pending"
        assert concise["assignee"] == "agent-1"
        assert concise["depends_on"] == ["loom-dep00001", "loom-dep00002"]
        assert concise["project_id"] == "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
        assert concise["parent_id"] is None

    def test_significantly_smaller(self):
        """Concise dict should be much smaller than full dict."""
        full = _make_task_dict()
        concise = _concise_task(full)
        # Full has all _HASH_FIELDS + depends_on; concise strips _VERBOSE_FIELDS
        assert len(concise) < len(full)
        # At minimum, _VERBOSE_FIELDS count of keys should be removed
        assert len(full) - len(concise) == len(
            [f for f in _VERBOSE_FIELDS if f in full]
        )

    def test_empty_context_still_stripped(self):
        """Even if context is empty dict, it should be stripped in concise mode."""
        full = _make_task_dict(context={})
        concise = _concise_task(full)
        assert "context" not in concise

    def test_preserves_dep_count(self):
        """depends_on list is preserved (agents need to know dependency count)."""
        full = _make_task_dict()
        concise = _concise_task(full)
        assert "depends_on" in concise
        assert len(concise["depends_on"]) == 2

    def test_idempotent(self):
        """Calling _concise_task on already-concise dict is safe."""
        full = _make_task_dict()
        concise1 = _concise_task(full)
        concise2 = _concise_task(concise1)
        assert concise1 == concise2


class TestVerboseFieldsCoverage:
    """Verify _VERBOSE_FIELDS is correct and complete."""

    def test_large_context_field_stripped(self):
        """The 'context' field (biggest token sink) must be in _VERBOSE_FIELDS."""
        assert "context" in _VERBOSE_FIELDS

    def test_output_field_stripped(self):
        """The 'output' field must be in _VERBOSE_FIELDS."""
        assert "output" in _VERBOSE_FIELDS

    def test_done_when_stripped(self):
        """The 'done_when' field must be in _VERBOSE_FIELDS."""
        assert "done_when" in _VERBOSE_FIELDS

    def test_timestamp_fields_stripped(self):
        """All timestamp fields should be in _VERBOSE_FIELDS."""
        for field in ("created_at", "updated_at", "claimed_at", "done_at",
                      "claim_expires_at", "last_failed_at", "retry_after"):
            assert field in _VERBOSE_FIELDS, f"Timestamp '{field}' should be stripped"

    def test_retry_fields_stripped(self):
        """Retry/dead-letter fields should be in _VERBOSE_FIELDS."""
        for field in ("retry_count", "max_retries", "dead_letter", "dead_letter_reason"):
            assert field in _VERBOSE_FIELDS, f"Retry field '{field}' should be stripped"

    def test_essential_fields_not_stripped(self):
        """Essential fields must NOT be in _VERBOSE_FIELDS."""
        essentials = {"id", "project_id", "title", "status", "priority",
                      "assignee", "parent_id", "depends_on"}
        for field in essentials:
            assert field not in _VERBOSE_FIELDS, (
                f"Essential field '{field}' must not be in _VERBOSE_FIELDS"
            )


class TestConciseTokenReduction:
    """Verify that concise mode achieves meaningful token reduction."""

    def test_large_context_stripped(self):
        """A task with large context should be much smaller in concise mode."""
        large_context = {
            "description": "x" * 500,
            "notes": "y" * 300,
            "testing": "z" * 200,
            "patterns": ["pattern"] * 20,
            "edge_cases": ["edge"] * 20,
            "complexity_reasoning": "w" * 400,
        }
        full = _make_task_dict(context=large_context)

        import json
        full_json = json.dumps(full)
        concise_json = json.dumps(_concise_task(full))

        # Concise should be dramatically smaller
        assert len(concise_json) < len(full_json) / 2, (
            f"Concise ({len(concise_json)} chars) should be less than half "
            f"of full ({len(full_json)} chars)"
        )

    def test_multiple_tasks_reduction(self):
        """Batch of tasks (like loom_ready returns) should see big reduction."""
        import json

        tasks = [
            _make_task_dict(
                task_id=f"loom-{i:08x}",
                context={"desc": f"{'x' * 200} task {i}", "notes": "y" * 100},
            )
            for i in range(10)
        ]

        full_json = json.dumps(tasks)
        concise_json = json.dumps([_concise_task(t) for t in tasks])

        # With 10 tasks, the reduction should be substantial
        assert len(concise_json) < len(full_json) / 2
