package copymission

import (
	"testing"

	libkg "haixun-backend/internal/library/knowledge"
	missionentity "haixun-backend/internal/model/copy_mission/domain/entity"
)

func TestMatrixKnowledgeItems_PrefersGraphSelection(t *testing.T) {
	nodes := []libkg.Node{
		{Label: "痛點A", NodeKind: "pain", SelectedForScan: true, PlacementValue: "細節A"},
		{Label: "周邊B", NodeKind: "context", SelectedForScan: false},
	}
	items := MatrixKnowledgeItems(nil, nil, nodes, nil)
	if len(items) != 1 {
		t.Fatalf("items = %v, want 1 selected graph node", items)
	}
	if items[0] != "痛點A｜細節A" {
		t.Fatalf("items[0] = %q", items[0])
	}
}

func TestMatrixKnowledgeItems_UsesMissionSelectionOnly(t *testing.T) {
	items := MatrixKnowledgeItems(
		[]string{"受眾問題：怎麼選"},
		[]string{"內容支柱：懶人包"},
		nil,
		nil,
	)
	if len(items) != 1 || items[0] != "受眾問題：怎麼選" {
		t.Fatalf("items = %v", items)
	}
}

func TestMatrixKnowledgeItems_MergesGraphAndMission(t *testing.T) {
	nodes := []libkg.Node{
		{
			Label:           "備孕營養",
			PlacementValue:  "葉酸與鋅很重要",
			SelectedForScan: true,
		},
		{
			Label:           "未勾選",
			PlacementValue:  "不應出現",
			SelectedForScan: false,
			DerivedTags: libkg.DerivedTags{
				Relevance: []string{"備孕飲食"},
			},
		},
	}
	items := MatrixKnowledgeItems(
		[]string{"手動補充：睡前習慣"},
		nil,
		nodes,
		[]string{"備孕飲食"},
	)
	if len(items) != 2 {
		t.Fatalf("items = %v", items)
	}
}

func TestMatrixKnowledgeItems_IgnoresUnselectedTagMatches(t *testing.T) {
	nodes := []libkg.Node{
		{
			Label:           "備孕營養",
			PlacementValue:  "葉酸與鋅很重要",
			SelectedForScan: false,
			DerivedTags: libkg.DerivedTags{
				Relevance: []string{"備孕飲食"},
			},
		},
	}
	items := MatrixKnowledgeItems(nil, nil, nodes, []string{"備孕飲食"})
	if len(items) != 0 {
		t.Fatalf("items = %v, want none without explicit selection", items)
	}
}

func TestBuildResearchMapFromGraph_RespectsManualDeselection(t *testing.T) {
	prev := missionentity.ResearchMap{
		KnowledgeItems:         []string{"圖譜痛點：細節"},
		SelectedKnowledgeItems: []string{},
	}
	out := BuildResearchMapFromGraph(prev, []libkg.Node{
		{Label: "圖譜痛點", NodeKind: "pain", SelectedForScan: true, PlacementValue: "細節"},
	}, nil)
	if len(out.SelectedKnowledgeItems) != 0 {
		t.Fatalf("selected = %v, want manual deselection honored", out.SelectedKnowledgeItems)
	}
}

func TestBuildResearchMapFromGraph_PreservesManualKnowledge(t *testing.T) {
	prev := missionentity.ResearchMap{
		KnowledgeItems:         []string{"手動知識：睡前"},
		SelectedKnowledgeItems: []string{"手動知識：睡前"},
	}
	out := BuildResearchMapFromGraph(prev, []libkg.Node{
		{Label: "圖譜痛點", NodeKind: "pain", SelectedForScan: true, PlacementValue: "細節"},
	}, nil)
	if len(out.KnowledgeItems) != 2 {
		t.Fatalf("knowledge_items = %v", out.KnowledgeItems)
	}
	if len(out.SelectedKnowledgeItems) != 2 {
		t.Fatalf("selected = %v", out.SelectedKnowledgeItems)
	}
}

func TestApplyDefaultNodeSelectionPreserving(t *testing.T) {
	nodes := []libkg.Node{
		{ID: "keep", Label: "已勾", NodeKind: "context", SelectedForScan: false},
		{ID: "new", Label: "新痛點", NodeKind: "pain", SelectedForScan: false},
	}
	ApplyDefaultNodeSelectionPreserving(nodes, map[string]bool{"keep": true})
	if !nodes[0].SelectedForScan {
		t.Fatal("expected preserved selection on existing node")
	}
	if !nodes[1].SelectedForScan {
		t.Fatal("expected default selection on new pain node")
	}
}