package semantic

import (
	"encoding/json"
	"testing"

	"github.com/stretchr/testify/require"
	"github.com/tidbcloud/AgentTeam/kits/agentteam-insight/internal/graphbuilder/schema"
)

func TestArchitectureSignalsPinnedUAGolden(t *testing.T) {
	graph := signalFixture()
	data, err := json.MarshalIndent(BuildArchitectureSignals(graph), "", "  ")
	require.NoError(t, err)
	require.JSONEq(t, `{
  "scriptCompleted": true,
  "directoryGroups": {"docs":["document:docs/guide.md"],"infra":["service:infra/Dockerfile"],"src":["file:src/main.go"],"tests":["file:tests/main_test.go"]},
  "nodeTypeGroups": {"document":["document:docs/guide.md"],"file":["file:src/main.go","file:tests/main_test.go"],"service":["service:infra/Dockerfile"]},
  "crossCategoryEdges": [{"fromType":"document","toType":"file","edgeType":"documents","count":1},{"fromType":"service","toType":"file","edgeType":"deploys","count":1}],
  "interGroupImports": [{"from":"tests","to":"src","count":1}],
  "intraGroupDensity": {"docs":{"internalEdges":0,"totalEdges":0,"density":0},"infra":{"internalEdges":0,"totalEdges":0,"density":0},"src":{"internalEdges":0,"totalEdges":1,"density":0},"tests":{"internalEdges":0,"totalEdges":1,"density":0}},
  "patternMatches": {"docs":"documentation","infra":"infrastructure","tests":"test"},
  "deploymentTopology":{"hasDockerfile":true,"hasCompose":false,"hasK8s":false,"hasTerraform":false,"hasCI":false,"infraFiles":["infra/Dockerfile"]},
  "dataPipeline":{"schemaFiles":[],"migrationFiles":[],"dataModelFiles":[],"apiHandlerFiles":[]},
  "docCoverage":{"groupsWithDocs":2,"totalGroups":4,"coverageRatio":0.5,"undocumentedGroups":["infra","tests"]},
  "dependencyDirection":[{"dependent":"tests","dependsOn":"src"}],
  "fileStats":{"totalFileNodes":4,"filesPerGroup":{"docs":1,"infra":1,"src":1,"tests":1},"nodeTypeCounts":{"document":1,"file":2,"service":1}},
  "fileFanIn":{"document:docs/guide.md":0,"file:src/main.go":1,"file:tests/main_test.go":0,"service:infra/Dockerfile":0},"fileFanOut":{"document:docs/guide.md":0,"file:src/main.go":0,"file:tests/main_test.go":1,"service:infra/Dockerfile":0}
}`, string(data))
}

func TestTourSignalsPinnedUAGolden(t *testing.T) {
	data, err := json.MarshalIndent(BuildTourSignals(signalFixture()), "", "  ")
	require.NoError(t, err)
	require.JSONEq(t, `{
  "scriptCompleted":true,
  "entryPointCandidates":[{"id":"file:src/main.go","score":4,"name":"main.go","summary":"entry"},{"id":"file:tests/main_test.go","score":3,"name":"main_test.go","summary":"test"}],
  "fanInRanking":[{"id":"file:src/main.go","fanIn":3,"fanOut":0,"name":"main.go"},{"id":"file:tests/main_test.go","fanIn":0,"fanOut":0,"name":"main_test.go"},{"id":"document:docs/guide.md","fanIn":0,"fanOut":0,"name":"guide.md"},{"id":"service:infra/Dockerfile","fanIn":0,"fanOut":0,"name":"Dockerfile"}],
  "fanOutRanking":[{"id":"file:tests/main_test.go","fanIn":0,"fanOut":1,"name":"main_test.go"},{"id":"document:docs/guide.md","fanIn":0,"fanOut":1,"name":"guide.md"},{"id":"service:infra/Dockerfile","fanIn":0,"fanOut":1,"name":"Dockerfile"},{"id":"file:src/main.go","fanIn":0,"fanOut":0,"name":"main.go"}],
  "bfsTraversal":{"startNode":"file:src/main.go","order":["file:src/main.go"],"depthMap":{"file:src/main.go":0},"byDepth":{"0":["file:src/main.go"]}},
  "nonCodeFiles":{"documentation":[{"id":"document:docs/guide.md","name":"guide.md","type":"document","summary":"guide"}],"infrastructure":[{"id":"service:infra/Dockerfile","name":"Dockerfile","type":"service","summary":"image"}],"data":[],"config":[]},
  "clusters":[],
  "layers":{"count":1,"list":[{"id":"layer:core","name":"Core","description":"core"}]},
  "nodeSummaryIndex":{"document:docs/guide.md":{"name":"guide.md","type":"document","summary":"guide"},"file:src/main.go":{"name":"main.go","type":"file","summary":"entry"},"file:tests/main_test.go":{"name":"main_test.go","type":"file","summary":"test"},"service:infra/Dockerfile":{"name":"Dockerfile","type":"service","summary":"image"}},
  "totalNodes":4,
  "totalEdges":3
}`, string(data))
}

func TestTourClustersExpandAgainstMembersAddedEarlierInSamePass(t *testing.T) {
	nodes := make([]schema.GraphNode, 0, 5)
	order := map[string]int{}
	for i, id := range []string{"a", "b", "c", "d", "e"} {
		nodes = append(nodes, schema.GraphNode{ID: id})
		order[id] = i
	}
	rel := map[string]map[string]map[string]bool{}
	connect := func(from, to string) {
		if rel[from] == nil {
			rel[from] = map[string]map[string]bool{}
		}
		rel[from][to] = map[string]bool{"imports": true}
	}
	connect("a", "b")
	connect("b", "a")
	connect("a", "c")
	connect("b", "c")
	connect("b", "d")
	connect("c", "d")
	connect("c", "e")
	connect("d", "e")

	require.Equal(t, []tourCluster{{Nodes: []string{"a", "b", "c", "d", "e"}, EdgeCount: 8}}, clusters(nodes, rel, order))
}

func TestSemanticPromptsUseGoSignalsWithoutScriptToolInstructions(t *testing.T) {
	graph, input := semanticFixture()
	architecture := BuildArchitecturePrompt(graph, input)
	tour := BuildTourPrompt(graph, input)
	for _, prompt := range []string{architecture, tour} {
		require.Contains(t, prompt, "computed by AgentTeam Insight Go")
		require.NotContains(t, prompt, "Write a script")
		require.NotContains(t, prompt, "node $UA_DIR")
		require.NotContains(t, prompt, "fall back to Python")
	}
}

func signalFixture() schema.KnowledgeGraph {
	return schema.KnowledgeGraph{Nodes: []schema.GraphNode{
		{ID: "file:src/main.go", Type: "file", Name: "main.go", FilePath: "src/main.go", Summary: "entry"},
		{ID: "file:tests/main_test.go", Type: "file", Name: "main_test.go", FilePath: "tests/main_test.go", Summary: "test"},
		{ID: "document:docs/guide.md", Type: "document", Name: "guide.md", FilePath: "docs/guide.md", Summary: "guide"},
		{ID: "service:infra/Dockerfile", Type: "service", Name: "Dockerfile", FilePath: "infra/Dockerfile", Summary: "image"},
	}, Edges: []schema.GraphEdge{
		{Source: "file:tests/main_test.go", Target: "file:src/main.go", Type: "imports"},
		{Source: "document:docs/guide.md", Target: "file:src/main.go", Type: "documents"},
		{Source: "service:infra/Dockerfile", Target: "file:src/main.go", Type: "deploys"},
	}, Layers: []schema.Layer{{ID: "layer:core", Name: "Core", Description: "core", NodeIDs: []string{"file:src/main.go"}}}}
}
