package mcp

import (
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func TestCreateSubtaskTool(t *testing.T) {
	deps := testDeps()
	// parent
	_, err := callTool(ctxWithAuth(Scope{}), deps, "create_issue", map[string]any{
		"project_slug": "test-project", "title": "Parent",
	})
	require.NoError(t, err)

	result, err := callTool(ctxWithAuth(Scope{}), deps, "create_subtask", map[string]any{
		"project_slug":  "test-project",
		"parent_number": float64(1),
		"title":         "Child",
		"priority":      float64(2),
	})
	require.NoError(t, err)
	assert.False(t, result.IsError)
	var out issueCreateOut
	unmarshalStructured(t, result, &out)
	assert.True(t, out.OK)
	assert.Equal(t, "Child", out.Issue.Title)
}

func TestAddListRemoveDependencyTool(t *testing.T) {
	deps := testDeps()
	for _, title := range []string{"A", "B"} {
		_, err := callTool(ctxWithAuth(Scope{}), deps, "create_issue", map[string]any{
			"project_slug": "test-project", "title": title,
		})
		require.NoError(t, err)
	}
	// A(#1) blocked-by B(#2)
	result, err := callTool(ctxWithAuth(Scope{}), deps, "add_dependency", map[string]any{
		"project_slug":   "test-project",
		"blocked_number": float64(1),
		"blocker_number": float64(2),
	})
	require.NoError(t, err)
	assert.False(t, result.IsError)
	var addOut dependencyOut
	unmarshalStructured(t, result, &addOut)
	assert.True(t, addOut.OK)

	// list_dependencies on A → blocked_by contains B
	result, err = callTool(ctxWithAuth(Scope{}), deps, "list_dependencies", map[string]any{
		"project_slug": "test-project", "number": float64(1),
	})
	require.NoError(t, err)
	var listOut listDependenciesOut
	unmarshalStructured(t, result, &listOut)
	require.Len(t, listOut.BlockedBy, 1)
	assert.Equal(t, 2, listOut.BlockedBy[0].Number)

	// remove
	result, err = callTool(ctxWithAuth(Scope{}), deps, "remove_dependency", map[string]any{
		"project_slug":   "test-project",
		"blocked_number": float64(1),
		"blocker_number": float64(2),
	})
	require.NoError(t, err)
	assert.False(t, result.IsError)

	result, err = callTool(ctxWithAuth(Scope{}), deps, "list_dependencies", map[string]any{
		"project_slug": "test-project", "number": float64(1),
	})
	require.NoError(t, err)
	unmarshalStructured(t, result, &listOut)
	assert.Empty(t, listOut.BlockedBy)
}

func TestAddDependencyTool_RejectsSelf(t *testing.T) {
	deps := testDeps()
	_, err := callTool(ctxWithAuth(Scope{}), deps, "create_issue", map[string]any{
		"project_slug": "test-project", "title": "A",
	})
	require.NoError(t, err)
	result, err := callTool(ctxWithAuth(Scope{}), deps, "add_dependency", map[string]any{
		"project_slug":   "test-project",
		"blocked_number": float64(1),
		"blocker_number": float64(1),
	})
	require.NoError(t, err)
	assert.True(t, result.IsError, "自依赖应被工具拒绝")
}

func TestSubmitDecompositionTool(t *testing.T) {
	deps := testDeps()
	// anchor parent
	_, err := callTool(ctxWithAuth(Scope{}), deps, "create_issue", map[string]any{
		"project_slug": "test-project", "title": "Anchor",
	})
	require.NoError(t, err)

	result, err := callTool(ctxWithAuth(Scope{}), deps, "submit_decomposition", map[string]any{
		"project_slug":  "test-project",
		"parent_number": float64(1),
		"subtasks": []any{
			map[string]any{"ref": "a", "title": "Task A", "priority": float64(2)},
			map[string]any{"ref": "b", "title": "Task B"},
		},
		"edges": []any{
			map[string]any{"blocked_ref": "a", "blocker_ref": "b"},
		},
	})
	require.NoError(t, err)
	assert.False(t, result.IsError)
	var out submitDecompositionOut
	unmarshalStructured(t, result, &out)
	assert.True(t, out.OK)
	require.Contains(t, out.RefToNumber, "a")
	require.Contains(t, out.RefToNumber, "b")
}

func TestSubmitDecompositionTool_RejectsCycle(t *testing.T) {
	deps := testDeps()
	result, err := callTool(ctxWithAuth(Scope{}), deps, "submit_decomposition", map[string]any{
		"project_slug": "test-project",
		"subtasks": []any{
			map[string]any{"ref": "a", "title": "A"},
			map[string]any{"ref": "b", "title": "B"},
		},
		"edges": []any{
			map[string]any{"blocked_ref": "a", "blocker_ref": "b"},
			map[string]any{"blocked_ref": "b", "blocker_ref": "a"},
		},
	})
	require.NoError(t, err)
	assert.True(t, result.IsError, "环应被拒绝")
}

func TestDecompositionToolsInSystemScope(t *testing.T) {
	// 新工具必须在 system token 默认白名单内，规划阶段 agent 才能调用。
	set := map[string]bool{}
	for _, name := range defaultSystemTools {
		set[name] = true
	}
	for _, name := range []string{
		"create_subtask", "add_dependency", "remove_dependency",
		"list_dependencies", "submit_decomposition",
	} {
		assert.True(t, set[name], "%s 应在 defaultSystemTools", name)
	}
	// create_acp_session 仍对 system token 禁用（不应在白名单）。
	assert.False(t, set["create_acp_session"], "create_acp_session 不应在 system 白名单")
}
