"""Real integration tests for MCP server using fastmcp.Client."""

import os
import shutil
import tempfile

import pytest
from fastmcp.client import Client

from beads_mcp.server import mcp


@pytest.fixture(scope="session")
def bd_executable():
    """Verify bd is available in PATH."""
    bd_path = shutil.which("bd")
    if not bd_path:
        pytest.fail(
            "bd executable not found in PATH. "
            "Please install bd or add it to your PATH before running integration tests."
        )
    return bd_path


@pytest.fixture
async def temp_db(bd_executable):
    """Create a temporary database file and initialize it - fully hermetic."""
    # Create temp directory that will serve as the workspace root
    temp_dir = tempfile.mkdtemp(prefix="beads_mcp_test_", dir="/tmp")

    # Initialize database in this directory (creates .beads/ subdirectory)
    import asyncio

    env = os.environ.copy()
    # Clear any existing BEADS_DIR/BEADS_DB to ensure clean state
    env.pop("BEADS_DB", None)
    env.pop("BEADS_DIR", None)

    # Run bd init in the temp directory - it will create .beads/ subdirectory
    process = await asyncio.create_subprocess_exec(
        bd_executable,
        "init",
        "--prefix",
        "test",
        stdout=asyncio.subprocess.PIPE,
        stderr=asyncio.subprocess.PIPE,
        env=env,
        cwd=temp_dir,  # Run in temp dir - bd init creates .beads/ here
    )
    stdout, stderr = await process.communicate()

    if process.returncode != 0:
        pytest.fail(f"Failed to initialize test database: {stderr.decode()}")

    # Return the .beads directory path (not the db file)
    beads_dir = os.path.join(temp_dir, ".beads")
    
    yield beads_dir

    # Cleanup
    shutil.rmtree(temp_dir, ignore_errors=True)


@pytest.fixture
async def mcp_client(bd_executable, temp_db, monkeypatch):
    """Create MCP client with temporary database."""
    from beads_mcp import tools

    # Reset connection pool before test
    tools._connection_pool.clear()

    # Reset context environment variables
    os.environ.pop("BEADS_CONTEXT_SET", None)
    os.environ.pop("BEADS_WORKING_DIR", None)
    os.environ.pop("BEADS_DB", None)
    os.environ.pop("BEADS_DIR", None)

    # temp_db is now the .beads directory path
    # The workspace root is the parent directory
    workspace_root = os.path.dirname(temp_db)

    # Disable daemon mode for tests (prevents daemon accumulation and timeouts)
    os.environ["BEADS_NO_DAEMON"] = "1"

    # Create test client
    async with Client(mcp) as client:
        # Automatically set context for the tests
        await client.call_tool("context", {"workspace_root": workspace_root})
        yield client

    # Reset connection pool and context after test
    tools._connection_pool.clear()
    os.environ.pop("BEADS_CONTEXT_SET", None)
    os.environ.pop("BEADS_WORKING_DIR", None)
    os.environ.pop("BEADS_DB", None)
    os.environ.pop("BEADS_DIR", None)
    os.environ.pop("BEADS_NO_DAEMON", None)


@pytest.mark.asyncio
async def test_quickstart_resource(mcp_client):
    """Test beads://quickstart resource."""
    result = await mcp_client.read_resource("beads://quickstart")

    assert result is not None
    content = result[0].text
    assert len(content) > 0
    assert "beads" in content.lower() or "bd" in content.lower()


@pytest.mark.asyncio
async def test_create_issue_tool(mcp_client):
    """Test create_issue tool."""
    result = await mcp_client.call_tool(
        "create",
        {
            "title": "Test MCP issue",
            "description": "Created via MCP server",
            "priority": 1,
            "issue_type": "bug",
            "brief": False,  # Get full Issue object
        },
    )

    # Parse the JSON response from CallToolResult
    import json

    issue_data = json.loads(result.content[0].text)
    assert issue_data["title"] == "Test MCP issue"
    assert issue_data["description"] == "Created via MCP server"
    assert issue_data["priority"] == 1
    assert issue_data["issue_type"] == "bug"
    assert issue_data["status"] == "open"
    assert "id" in issue_data

    return issue_data["id"]


@pytest.mark.asyncio
async def test_show_issue_tool(mcp_client):
    """Test show_issue tool."""
    # First create an issue
    create_result = await mcp_client.call_tool(
        "create",
        {"title": "Issue to show", "priority": 2, "issue_type": "task", "brief": False},
    )
    import json

    created = json.loads(create_result.content[0].text)
    issue_id = created["id"]

    # Show the issue
    show_result = await mcp_client.call_tool("show", {"issue_id": issue_id})

    issue = json.loads(show_result.content[0].text)
    assert issue["id"] == issue_id
    assert issue["title"] == "Issue to show"


@pytest.mark.asyncio
async def test_list_issues_tool(mcp_client):
    """Test list_issues tool."""
    # Create some issues first
    await mcp_client.call_tool(
        "create", {"title": "Issue 1", "priority": 0, "issue_type": "bug", "brief": False}
    )
    await mcp_client.call_tool(
        "create", {"title": "Issue 2", "priority": 1, "issue_type": "feature", "brief": False}
    )

    # List all issues
    result = await mcp_client.call_tool("list", {})

    import json

    issues = json.loads(result.content[0].text)
    assert len(issues) >= 2

    # List with status filter
    result = await mcp_client.call_tool("list", {"status": "open"})
    issues = json.loads(result.content[0].text)
    assert all(issue["status"] == "open" for issue in issues)


@pytest.mark.asyncio
async def test_update_issue_tool(mcp_client):
    """Test update_issue tool."""
    import json

    # Create issue
    create_result = await mcp_client.call_tool(
        "create", {"title": "Issue to update", "priority": 2, "issue_type": "task", "brief": False}
    )
    created = json.loads(create_result.content[0].text)
    issue_id = created["id"]

    # Update issue
    update_result = await mcp_client.call_tool(
        "update",
        {
            "issue_id": issue_id,
            "status": "in_progress",
            "priority": 0,
            "title": "Updated title",
            "brief": False,  # Get full Issue object
        },
    )

    updated = json.loads(update_result.content[0].text)
    assert updated["id"] == issue_id
    assert updated["status"] == "in_progress"
    assert updated["priority"] == 0
    assert updated["title"] == "Updated title"


@pytest.mark.asyncio
async def test_close_issue_tool(mcp_client):
    """Test close_issue tool."""
    import json

    # Create issue
    create_result = await mcp_client.call_tool(
        "create", {"title": "Issue to close", "priority": 1, "issue_type": "bug", "brief": False}
    )
    created = json.loads(create_result.content[0].text)
    issue_id = created["id"]

    # Close issue with brief=False to get full Issue object
    close_result = await mcp_client.call_tool(
        "close", {"issue_id": issue_id, "reason": "Test complete", "brief": False}
    )

    closed_issues = json.loads(close_result.content[0].text)
    assert len(closed_issues) >= 1
    closed = closed_issues[0]
    assert closed["id"] == issue_id
    assert closed["status"] == "closed"
    assert closed["closed_at"] is not None


@pytest.mark.asyncio
async def test_reopen_issue_tool(mcp_client):
    """Test reopen_issue tool."""
    import json

    # Create and close issue
    create_result = await mcp_client.call_tool(
        "create", {"title": "Issue to reopen", "priority": 1, "issue_type": "bug", "brief": False}
    )
    created = json.loads(create_result.content[0].text)
    issue_id = created["id"]

    await mcp_client.call_tool(
        "close", {"issue_id": issue_id, "reason": "Done"}
    )

    # Reopen issue with brief=False to get full Issue object
    reopen_result = await mcp_client.call_tool(
        "reopen", {"issue_ids": [issue_id], "brief": False}
    )

    reopened_issues = json.loads(reopen_result.content[0].text)
    assert len(reopened_issues) >= 1
    reopened = reopened_issues[0]
    assert reopened["id"] == issue_id
    assert reopened["status"] == "open"
    assert reopened["closed_at"] is None


@pytest.mark.asyncio
async def test_reopen_multiple_issues_tool(mcp_client):
    """Test reopening multiple issues via MCP tool."""
    import json

    # Create and close two issues
    issue1_result = await mcp_client.call_tool(
        "create", {"title": "Issue 1 to reopen", "priority": 1, "issue_type": "task", "brief": False}
    )
    issue1 = json.loads(issue1_result.content[0].text)

    issue2_result = await mcp_client.call_tool(
        "create", {"title": "Issue 2 to reopen", "priority": 1, "issue_type": "task", "brief": False}
    )
    issue2 = json.loads(issue2_result.content[0].text)

    await mcp_client.call_tool("close", {"issue_id": issue1["id"], "reason": "Done"})
    await mcp_client.call_tool("close", {"issue_id": issue2["id"], "reason": "Done"})

    # Reopen both issues with brief=False
    reopen_result = await mcp_client.call_tool(
        "reopen", {"issue_ids": [issue1["id"], issue2["id"]], "brief": False}
    )

    reopened_issues = json.loads(reopen_result.content[0].text)
    assert len(reopened_issues) == 2
    reopened_ids = {issue["id"] for issue in reopened_issues}
    assert issue1["id"] in reopened_ids
    assert issue2["id"] in reopened_ids
    assert all(issue["status"] == "open" for issue in reopened_issues)
    assert all(issue["closed_at"] is None for issue in reopened_issues)


@pytest.mark.asyncio
async def test_reopen_with_reason_tool(mcp_client):
    """Test reopening issue with reason parameter via MCP tool."""
    import json

    # Create and close issue
    create_result = await mcp_client.call_tool(
        "create", {"title": "Issue to reopen with reason", "priority": 1, "issue_type": "bug", "brief": False}
    )
    created = json.loads(create_result.content[0].text)
    issue_id = created["id"]

    await mcp_client.call_tool("close", {"issue_id": issue_id, "reason": "Done"})

    # Reopen with reason and brief=False
    reopen_result = await mcp_client.call_tool(
        "reopen",
        {"issue_ids": [issue_id], "reason": "Found regression", "brief": False}
    )

    reopened_issues = json.loads(reopen_result.content[0].text)
    assert len(reopened_issues) >= 1
    reopened = reopened_issues[0]
    assert reopened["id"] == issue_id
    assert reopened["status"] == "open"
    assert reopened["closed_at"] is None


@pytest.mark.asyncio
async def test_ready_work_tool(mcp_client):
    """Test ready_work tool."""
    import json

    # Create a ready issue (no dependencies)
    ready_result = await mcp_client.call_tool(
        "create", {"title": "Ready work", "priority": 1, "issue_type": "task", "brief": False}
    )
    ready_issue = json.loads(ready_result.content[0].text)

    # Create blocked issue
    blocking_result = await mcp_client.call_tool(
        "create", {"title": "Blocking issue", "priority": 1, "issue_type": "task", "brief": False}
    )
    blocking_issue = json.loads(blocking_result.content[0].text)

    blocked_result = await mcp_client.call_tool(
        "create", {"title": "Blocked issue", "priority": 1, "issue_type": "task", "brief": False}
    )
    blocked_issue = json.loads(blocked_result.content[0].text)

    # Add blocking dependency
    await mcp_client.call_tool(
        "dep",
        {
            "issue_id": blocked_issue["id"],
            "depends_on_id": blocking_issue["id"],
            "dep_type": "blocks",
        },
    )

    # Get ready work
    result = await mcp_client.call_tool("ready", {"limit": 100})
    ready_issues = json.loads(result.content[0].text)

    ready_ids = [issue["id"] for issue in ready_issues]
    assert ready_issue["id"] in ready_ids
    assert blocked_issue["id"] not in ready_ids


@pytest.mark.asyncio
async def test_add_dependency_tool(mcp_client):
    """Test add_dependency tool."""
    import json

    # Create two issues
    issue1_result = await mcp_client.call_tool(
        "create", {"title": "Issue 1", "priority": 1, "issue_type": "task", "brief": False}
    )
    issue1 = json.loads(issue1_result.content[0].text)

    issue2_result = await mcp_client.call_tool(
        "create", {"title": "Issue 2", "priority": 1, "issue_type": "task", "brief": False}
    )
    issue2 = json.loads(issue2_result.content[0].text)

    # Add dependency
    result = await mcp_client.call_tool(
        "dep",
        {"issue_id": issue1["id"], "depends_on_id": issue2["id"], "dep_type": "blocks"},
    )

    message = result.content[0].text
    assert "Added dependency" in message
    assert issue1["id"] in message
    assert issue2["id"] in message


@pytest.mark.asyncio
async def test_create_with_all_fields(mcp_client):
    """Test create_issue with all optional fields."""
    import json

    result = await mcp_client.call_tool(
        "create",
        {
            "title": "Full issue",
            "description": "Complete description",
            "priority": 0,
            "issue_type": "feature",
            "assignee": "testuser",
            "labels": ["urgent", "backend"],
            "brief": False,  # Get full Issue object
        },
    )

    issue = json.loads(result.content[0].text)
    assert issue["title"] == "Full issue"
    assert issue["description"] == "Complete description"
    assert issue["priority"] == 0
    assert issue["issue_type"] == "feature"
    assert issue["assignee"] == "testuser"


@pytest.mark.asyncio
async def test_list_with_filters(mcp_client):
    """Test list_issues with various filters."""
    import json

    # Create issues with different attributes
    await mcp_client.call_tool(
        "create",
        {
            "title": "Bug P0",
            "priority": 0,
            "issue_type": "bug",
            "assignee": "alice",
            "brief": False,
        },
    )
    await mcp_client.call_tool(
        "create",
        {
            "title": "Feature P1",
            "priority": 1,
            "issue_type": "feature",
            "assignee": "bob",
            "brief": False,
        },
    )

    # Filter by priority
    result = await mcp_client.call_tool("list", {"priority": 0})
    issues = json.loads(result.content[0].text)
    assert all(issue["priority"] == 0 for issue in issues)

    # Filter by type
    result = await mcp_client.call_tool("list", {"issue_type": "bug"})
    issues = json.loads(result.content[0].text)
    assert all(issue["issue_type"] == "bug" for issue in issues)

    # Filter by assignee
    result = await mcp_client.call_tool("list", {"assignee": "alice"})
    issues = json.loads(result.content[0].text)
    assert all(issue["assignee"] == "alice" for issue in issues)


@pytest.mark.asyncio
async def test_ready_work_with_priority_filter(mcp_client):
    """Test ready_work with priority filter."""
    import json

    # Create issues with different priorities
    await mcp_client.call_tool(
        "create", {"title": "P0 issue", "priority": 0, "issue_type": "bug", "brief": False}
    )
    await mcp_client.call_tool(
        "create", {"title": "P1 issue", "priority": 1, "issue_type": "task", "brief": False}
    )

    # Get ready work with priority filter
    result = await mcp_client.call_tool("ready", {"priority": 0, "limit": 100})
    issues = json.loads(result.content[0].text)
    assert all(issue["priority"] == 0 for issue in issues)


@pytest.mark.asyncio
async def test_update_partial_fields(mcp_client):
    """Test update_issue with partial field updates."""
    import json

    # Create issue
    create_result = await mcp_client.call_tool(
        "create",
        {
            "title": "Original title",
            "description": "Original description",
            "priority": 2,
            "issue_type": "task",
            "brief": False,
        },
    )
    created = json.loads(create_result.content[0].text)
    issue_id = created["id"]

    # Update only status with brief=False to get full Issue
    update_result = await mcp_client.call_tool(
        "update", {"issue_id": issue_id, "status": "in_progress", "brief": False}
    )
    updated = json.loads(update_result.content[0].text)
    assert updated["status"] == "in_progress"
    assert updated["title"] == "Original title"  # Unchanged
    assert updated["priority"] == 2  # Unchanged


@pytest.mark.asyncio
async def test_dependency_types(mcp_client):
    """Test different dependency types."""
    import json

    # Create issues
    issue1_result = await mcp_client.call_tool(
        "create", {"title": "Issue 1", "priority": 1, "issue_type": "task", "brief": False}
    )
    issue1 = json.loads(issue1_result.content[0].text)

    issue2_result = await mcp_client.call_tool(
        "create", {"title": "Issue 2", "priority": 1, "issue_type": "task", "brief": False}
    )
    issue2 = json.loads(issue2_result.content[0].text)

    # Test related dependency
    result = await mcp_client.call_tool(
        "dep",
        {"issue_id": issue1["id"], "depends_on_id": issue2["id"], "dep_type": "related"},
    )

    message = result.content[0].text
    assert "Added dependency" in message
    assert "related" in message


@pytest.mark.asyncio
async def test_stats_tool(mcp_client):
    """Test stats tool."""
    import json

    # Create some issues to get stats
    await mcp_client.call_tool(
        "create", {"title": "Stats test 1", "priority": 1, "issue_type": "bug", "brief": False}
    )
    await mcp_client.call_tool(
        "create", {"title": "Stats test 2", "priority": 2, "issue_type": "task", "brief": False}
    )

    # Get stats
    result = await mcp_client.call_tool("stats", {})
    stats = json.loads(result.content[0].text)

    assert "total_issues" in stats
    assert "open_issues" in stats
    assert stats["total_issues"] >= 2


@pytest.mark.asyncio
async def test_blocked_tool(mcp_client):
    """Test blocked tool."""
    import json

    # Create two issues
    blocking_result = await mcp_client.call_tool(
        "create", {"title": "Blocking issue", "priority": 1, "issue_type": "task", "brief": False}
    )
    blocking_issue = json.loads(blocking_result.content[0].text)

    blocked_result = await mcp_client.call_tool(
        "create", {"title": "Blocked issue", "priority": 1, "issue_type": "task", "brief": False}
    )
    blocked_issue = json.loads(blocked_result.content[0].text)

    # Add blocking dependency
    await mcp_client.call_tool(
        "dep",
        {
            "issue_id": blocked_issue["id"],
            "depends_on_id": blocking_issue["id"],
            "dep_type": "blocks",
        },
    )

    # Get blocked issues
    result = await mcp_client.call_tool("blocked", {})
    blocked_issues = json.loads(result.content[0].text)

    # Should have at least the one we created
    blocked_ids = [issue["id"] for issue in blocked_issues]
    assert blocked_issue["id"] in blocked_ids

    # Find our blocked issue and verify it has blocking info
    our_blocked = next(issue for issue in blocked_issues if issue["id"] == blocked_issue["id"])
    assert our_blocked["blocked_by_count"] >= 1
    assert blocking_issue["id"] in our_blocked["blocked_by"]


@pytest.mark.asyncio
async def test_context_init_action(bd_executable):
    """Test context tool with init action.

    Note: This test validates that context(action='init') can be called successfully via MCP.
    Uses a fresh temp directory without an existing database.
    """
    import os
    import tempfile
    import shutil
    from beads_mcp import tools
    from beads_mcp.server import mcp

    # Reset connection pool and context
    tools._connection_pool.clear()
    os.environ.pop("BEADS_CONTEXT_SET", None)
    os.environ.pop("BEADS_WORKING_DIR", None)
    os.environ.pop("BEADS_DB", None)
    os.environ.pop("BEADS_DIR", None)
    os.environ["BEADS_NO_DAEMON"] = "1"

    # Create a fresh temp directory without any beads database
    temp_dir = tempfile.mkdtemp(prefix="beads_init_test_")
    try:
        async with Client(mcp) as client:
            # First set context to the fresh directory
            await client.call_tool("context", {"workspace_root": temp_dir})

            # Call context tool with init action
            result = await client.call_tool("context", {"action": "init", "prefix": "test-init"})
            output = result.content[0].text

            # Verify output contains success message
            assert "bd initialized successfully!" in output
            assert "test-init" in output
    finally:
        tools._connection_pool.clear()
        shutil.rmtree(temp_dir, ignore_errors=True)
        os.environ.pop("BEADS_CONTEXT_SET", None)
        os.environ.pop("BEADS_WORKING_DIR", None)


@pytest.mark.asyncio
async def test_context_show_action(mcp_client, temp_db):
    """Test context tool with show action.

    Verifies that context(action='show') returns workspace information.
    """
    # Call context tool with show action (default when no args)
    result = await mcp_client.call_tool("context", {"action": "show"})
    output = result.content[0].text

    # Verify output contains workspace info
    assert "Workspace root:" in output
    assert "Database:" in output


@pytest.mark.asyncio
async def test_context_default_show(mcp_client, temp_db):
    """Test context tool defaults to show when no args provided."""
    # Call context tool with no args - should default to show
    result = await mcp_client.call_tool("context", {})
    output = result.content[0].text

    # Verify output contains workspace info (same as show action)
    assert "Workspace root:" in output
    assert "Database:" in output


# =============================================================================
# OUTPUT CONTROL PARAMETER TESTS
# =============================================================================


@pytest.mark.asyncio
async def test_create_brief_default(mcp_client):
    """Test create returns OperationResult by default (brief=True)."""
    import json

    result = await mcp_client.call_tool(
        "create",
        {"title": "Brief test issue", "priority": 2, "issue_type": "task"},
    )

    data = json.loads(result.content[0].text)
    # Default brief=True returns OperationResult
    assert "id" in data
    assert data["action"] == "created"
    # Should NOT have full Issue fields
    assert "title" not in data
    assert "description" not in data


@pytest.mark.asyncio
async def test_create_brief_false(mcp_client):
    """Test create returns full Issue when brief=False."""
    import json

    result = await mcp_client.call_tool(
        "create",
        {
            "title": "Full issue test",
            "description": "Full description",
            "priority": 1,
            "issue_type": "bug",
            "brief": False,
        },
    )

    data = json.loads(result.content[0].text)
    # brief=False returns full Issue
    assert data["title"] == "Full issue test"
    assert data["description"] == "Full description"
    assert data["priority"] == 1
    assert data["issue_type"] == "bug"
    assert data["status"] == "open"


@pytest.mark.asyncio
async def test_update_brief_default(mcp_client):
    """Test update returns OperationResult by default (brief=True)."""
    import json

    # Create issue first
    create_result = await mcp_client.call_tool(
        "create", {"title": "Update brief test", "brief": False}
    )
    created = json.loads(create_result.content[0].text)
    issue_id = created["id"]

    # Update with default brief=True
    update_result = await mcp_client.call_tool(
        "update", {"issue_id": issue_id, "status": "in_progress"}
    )

    data = json.loads(update_result.content[0].text)
    assert data["id"] == issue_id
    assert data["action"] == "updated"
    assert "title" not in data


@pytest.mark.asyncio
async def test_update_brief_false(mcp_client):
    """Test update returns full Issue when brief=False."""
    import json

    # Create issue first
    create_result = await mcp_client.call_tool(
        "create", {"title": "Update full test", "brief": False}
    )
    created = json.loads(create_result.content[0].text)
    issue_id = created["id"]

    # Update with brief=False
    update_result = await mcp_client.call_tool(
        "update", {"issue_id": issue_id, "status": "in_progress", "brief": False}
    )

    data = json.loads(update_result.content[0].text)
    assert data["id"] == issue_id
    assert data["status"] == "in_progress"
    assert data["title"] == "Update full test"


@pytest.mark.asyncio
async def test_close_brief_default(mcp_client):
    """Test close returns OperationResult by default (brief=True)."""
    import json

    # Create issue first
    create_result = await mcp_client.call_tool(
        "create", {"title": "Close brief test", "brief": False}
    )
    created = json.loads(create_result.content[0].text)
    issue_id = created["id"]

    # Close with default brief=True
    close_result = await mcp_client.call_tool(
        "close", {"issue_id": issue_id, "reason": "Done"}
    )

    data = json.loads(close_result.content[0].text)
    assert isinstance(data, list)
    assert len(data) == 1
    assert data[0]["id"] == issue_id
    assert data[0]["action"] == "closed"


@pytest.mark.asyncio
async def test_close_brief_false(mcp_client):
    """Test close returns full Issue when brief=False."""
    import json

    # Create issue first
    create_result = await mcp_client.call_tool(
        "create", {"title": "Close full test", "brief": False}
    )
    created = json.loads(create_result.content[0].text)
    issue_id = created["id"]

    # Close with brief=False
    close_result = await mcp_client.call_tool(
        "close", {"issue_id": issue_id, "reason": "Done", "brief": False}
    )

    data = json.loads(close_result.content[0].text)
    assert isinstance(data, list)
    assert len(data) >= 1
    assert data[0]["id"] == issue_id
    assert data[0]["status"] == "closed"
    assert data[0]["title"] == "Close full test"


@pytest.mark.asyncio
async def test_reopen_brief_default(mcp_client):
    """Test reopen returns OperationResult by default (brief=True)."""
    import json

    # Create and close issue first
    create_result = await mcp_client.call_tool(
        "create", {"title": "Reopen brief test", "brief": False}
    )
    created = json.loads(create_result.content[0].text)
    issue_id = created["id"]

    await mcp_client.call_tool("close", {"issue_id": issue_id})

    # Reopen with default brief=True
    reopen_result = await mcp_client.call_tool(
        "reopen", {"issue_ids": [issue_id]}
    )

    data = json.loads(reopen_result.content[0].text)
    assert isinstance(data, list)
    assert len(data) == 1
    assert data[0]["id"] == issue_id
    assert data[0]["action"] == "reopened"


@pytest.mark.asyncio
async def test_show_brief(mcp_client):
    """Test show with brief=True returns BriefIssue."""
    import json

    # Create issue first
    create_result = await mcp_client.call_tool(
        "create",
        {"title": "Show brief test", "description": "Long description", "brief": False},
    )
    created = json.loads(create_result.content[0].text)
    issue_id = created["id"]

    # Show with brief=True
    show_result = await mcp_client.call_tool(
        "show", {"issue_id": issue_id, "brief": True}
    )

    data = json.loads(show_result.content[0].text)
    # BriefIssue has only: id, title, status, priority
    assert data["id"] == issue_id
    assert data["title"] == "Show brief test"
    assert data["status"] == "open"
    assert "priority" in data
    # Should NOT have full Issue fields
    assert "description" not in data
    assert "dependencies" not in data


@pytest.mark.asyncio
async def test_show_fields_projection(mcp_client):
    """Test show with fields parameter for custom projection."""
    import json

    # Create issue first
    create_result = await mcp_client.call_tool(
        "create",
        {
            "title": "Fields test",
            "description": "Test description",
            "priority": 1,
            "brief": False,
        },
    )
    created = json.loads(create_result.content[0].text)
    issue_id = created["id"]

    # Show with specific fields
    show_result = await mcp_client.call_tool(
        "show", {"issue_id": issue_id, "fields": ["id", "title", "priority"]}
    )

    data = json.loads(show_result.content[0].text)
    # Should have only requested fields
    assert data["id"] == issue_id
    assert data["title"] == "Fields test"
    assert data["priority"] == 1
    # Should NOT have other fields
    assert "description" not in data
    assert "status" not in data


@pytest.mark.asyncio
async def test_show_fields_invalid(mcp_client):
    """Test show with invalid fields raises error."""
    import json
    from fastmcp.exceptions import ToolError

    # Create issue first
    create_result = await mcp_client.call_tool(
        "create", {"title": "Invalid fields test", "brief": False}
    )
    created = json.loads(create_result.content[0].text)
    issue_id = created["id"]

    # Show with invalid field should raise ToolError
    with pytest.raises(ToolError) as exc_info:
        await mcp_client.call_tool(
            "show", {"issue_id": issue_id, "fields": ["id", "nonexistent_field"]}
        )

    # Verify error message mentions invalid field
    assert "Invalid field" in str(exc_info.value)


@pytest.mark.asyncio
async def test_show_max_description_length(mcp_client):
    """Test show with max_description_length truncates description."""
    import json

    # Create issue with long description
    long_desc = "A" * 200
    create_result = await mcp_client.call_tool(
        "create",
        {"title": "Truncate test", "description": long_desc, "brief": False},
    )
    created = json.loads(create_result.content[0].text)
    issue_id = created["id"]

    # Show with truncation
    show_result = await mcp_client.call_tool(
        "show", {"issue_id": issue_id, "max_description_length": 50}
    )

    data = json.loads(show_result.content[0].text)
    # Description should be truncated
    assert len(data["description"]) <= 53  # 50 + "..."
    assert data["description"].endswith("...")


@pytest.mark.asyncio
async def test_list_brief(mcp_client):
    """Test list with brief=True returns BriefIssue format."""
    import json

    # Create some issues
    await mcp_client.call_tool(
        "create", {"title": "List brief 1", "priority": 1, "brief": False}
    )
    await mcp_client.call_tool(
        "create", {"title": "List brief 2", "priority": 2, "brief": False}
    )

    # List with brief=True
    result = await mcp_client.call_tool("list", {"brief": True})
    issues = json.loads(result.content[0].text)

    assert len(issues) >= 2
    for issue in issues:
        # BriefIssue has only: id, title, status, priority
        assert "id" in issue
        assert "title" in issue
        assert "status" in issue
        assert "priority" in issue
        # Should NOT have full Issue fields
        assert "description" not in issue
        assert "issue_type" not in issue


@pytest.mark.asyncio
async def test_ready_brief(mcp_client):
    """Test ready with brief=True returns BriefIssue format."""
    import json

    # Create a ready issue
    await mcp_client.call_tool(
        "create", {"title": "Ready brief test", "priority": 1, "brief": False}
    )

    # Ready with brief=True
    result = await mcp_client.call_tool("ready", {"brief": True, "limit": 100})
    issues = json.loads(result.content[0].text)

    assert len(issues) >= 1
    for issue in issues:
        # BriefIssue has only: id, title, status, priority
        assert "id" in issue
        assert "title" in issue
        assert "status" in issue
        assert "priority" in issue
        # Should NOT have full Issue fields
        assert "description" not in issue


@pytest.mark.asyncio
async def test_blocked_brief(mcp_client):
    """Test blocked with brief=True returns BriefIssue format."""
    import json

    # Create blocking dependency
    blocking_result = await mcp_client.call_tool(
        "create", {"title": "Blocker for brief test", "brief": False}
    )
    blocking = json.loads(blocking_result.content[0].text)

    blocked_result = await mcp_client.call_tool(
        "create", {"title": "Blocked for brief test", "brief": False}
    )
    blocked = json.loads(blocked_result.content[0].text)

    await mcp_client.call_tool(
        "dep",
        {"issue_id": blocked["id"], "depends_on_id": blocking["id"], "dep_type": "blocks"},
    )

    # Blocked with brief=True
    result = await mcp_client.call_tool("blocked", {"brief": True})
    issues = json.loads(result.content[0].text)

    # Find our blocked issue
    our_blocked = [i for i in issues if i["id"] == blocked["id"]]
    assert len(our_blocked) == 1
    # BriefIssue format
    assert "title" in our_blocked[0]
    assert "status" in our_blocked[0]
    # Should NOT have BlockedIssue-specific fields
    assert "blocked_by" not in our_blocked[0]


@pytest.mark.asyncio
async def test_show_brief_deps(mcp_client):
    """Test show with brief_deps=True returns compact dependencies."""
    import json

    # Create two issues with dependency
    dep_result = await mcp_client.call_tool(
        "create", {"title": "Dependency issue", "brief": False}
    )
    dep_issue = json.loads(dep_result.content[0].text)

    main_result = await mcp_client.call_tool(
        "create", {"title": "Main issue", "brief": False}
    )
    main_issue = json.loads(main_result.content[0].text)

    await mcp_client.call_tool(
        "dep",
        {"issue_id": main_issue["id"], "depends_on_id": dep_issue["id"], "dep_type": "blocks"},
    )

    # Show with brief_deps=True
    show_result = await mcp_client.call_tool(
        "show", {"issue_id": main_issue["id"], "brief_deps": True}
    )

    data = json.loads(show_result.content[0].text)
    # Full issue data
    assert data["id"] == main_issue["id"]
    assert data["title"] == "Main issue"
    # Dependencies should be compact (BriefDep format)
    assert len(data["dependencies"]) >= 1
    dep = data["dependencies"][0]
    assert "id" in dep
    assert "title" in dep
    assert "status" in dep
    # BriefDep should NOT have full LinkedIssue fields
    assert "description" not in dep
