package usecase

import (
	"strings"
	"testing"
)

func TestTopicSignatureExcludesAnchorsAndKeepsNamedEntity(t *testing.T) {
	sig := NewTopicSignature("鬼滅之刃", []string{"鬼滅之刃 最新", "鬼滅 分享"})
	if len(sig.Concepts) != 1 {
		t.Fatalf("concepts=%+v, want one named-entity concept", sig.Concepts)
	}
	if !sig.Matches("鬼滅之刃最新一集大家都在討論") {
		t.Fatal("named entity should match")
	}
	if sig.Matches("最近想看動畫，有推薦熱門作品嗎") {
		t.Fatal("generic recommendation must not bypass entity gate")
	}
	if len(sig.Concepts[0].Aliases) != 1 || sig.Concepts[0].Aliases[0] != "鬼滅" {
		t.Fatalf("aliases=%+v, want explicit 鬼滅 alias", sig.Concepts[0].Aliases)
	}
}

func TestTopicSignatureRequiresEveryConceptGroup(t *testing.T) {
	sig := BuildTopicSignature("外包 後端工程師", []string{"後端 外包", "後端工程師 推薦"})
	if len(sig.Concepts) != 2 {
		t.Fatalf("concepts=%+v, want outsourcing and backend groups", sig.Concepts)
	}
	if !sig.Matches("想找後端工程師做外包合作，有推薦的接案夥伴嗎") {
		t.Fatal("candidate with both concepts should match")
	}
	missing := sig.Match("請問一般工程師轉職需要準備什麼")
	if missing.Matched || len(missing.MissingGroups) != 2 {
		t.Fatalf("missing concepts were not rejected: %+v", missing)
	}
	if sig.Matches("正在找後端工程師轉職") {
		t.Fatal("explicitly missing outsourcing concept should fail")
	}
}

func TestTopicSignatureDoesNotTurnConjunctionFragmentsIntoAliases(t *testing.T) {
	sig := NewTopicSignature("外包 後端工程師", []string{"後端 外包"})
	if sig.Matches("有人分享後端外包合作經驗") {
		t.Fatal("a conjunction fragment must not alias 後端工程師")
	}
	if !sig.Matches("有人分享後端工程師外包合作經驗") {
		t.Fatal("full backend-engineer and outsourcing concepts should match")
	}
}

func TestTopicSignatureUsesApprovedSplitAndLatinCase(t *testing.T) {
	sig := NewTopicSignature("台北週末市集", []string{"台北 市集", "週末 市集"})
	if len(sig.Concepts) != 3 {
		t.Fatalf("split concepts=%+v, want city/weekend/market", sig.Concepts)
	}
	if !sig.Matches("這週末台北有沒有適合拍照的市集？") {
		t.Fatal("approved split concepts should match natural sentence")
	}
	if sig.Matches("台北週末天氣好像會下雨") {
		t.Fatal("weather post missing market concept")
	}
	latin := NewTopicSignature("OpenAI API", []string{"openai api"})
	if !latin.Matches("請問 OPENAI API 要怎麼申請") {
		t.Fatal("latin topic matching should ignore case")
	}
}

func TestTopicSignatureDecomposesNaturalIntentWithoutRequiringWholeSentence(t *testing.T) {
	sig := NewTopicSignature("想找台北週末市集可以拍什麼", []string{"台北 市集", "週末 市集"})
	if len(sig.Concepts) != 2 {
		t.Fatalf("natural concepts=%+v, want location and topic", sig.Concepts)
	}
	if !sig.Matches("台北這週有市集活動，適合拍照") {
		t.Fatal("natural sentence should match its meaningful concepts")
	}
	if sig.Matches("台北這週有咖啡活動，適合拍照") {
		t.Fatal("different topic should remain irrelevant")
	}
}

func TestTopicSignatureKeepsNaturalWorkConceptsButDropsGeneratedVariants(t *testing.T) {
	sig := NewTopicSignature("找後端工程師接案", []string{"後端 外包", "後端 接案", "後端 工程師"})
	if len(sig.Concepts) != 3 {
		t.Fatalf("work concepts=%+v, want backend/engineer/freelance", sig.Concepts)
	}
	if !sig.Matches("正在找後端工程師接案夥伴") {
		t.Fatal("natural work intent should match")
	}
	if !sig.Matches("正在找後端工程師做外包合作") {
		t.Fatal("接案 and 外包 should be bounded work-intent synonyms")
	}
	if sig.Matches("正在找前端工程師接案夥伴") {
		t.Fatal("different specialty should remain irrelevant")
	}
}

func TestTopicSignatureExtractsTopicFromQuestionLikeIntent(t *testing.T) {
	sig := NewTopicSignature("週末有插座", []string{"插座 求推薦", "咖啡 插座"})
	if len(sig.Concepts) != 1 || !sig.Matches("請問這間咖啡店週末有插座嗎？") {
		t.Fatalf("question-like intent signature=%+v", sig)
	}
}

func TestTopicSignatureExtractsNamedEntityAfterRecommendationPhrase(t *testing.T) {
	sig := NewTopicSignature("推薦鬼滅之刃", []string{"鬼滅之刃 最新", "鬼滅 分享"})
	if len(sig.Concepts) != 1 || !sig.Matches("最近在討論鬼滅之刃最新一集") {
		t.Fatalf("recommendation phrase signature=%+v", sig)
	}
}

func TestTopicSignatureReasonNamesMatchedCores(t *testing.T) {
	sig := NewTopicSignature("外包 後端", nil)
	match := sig.Match("後端工程師正在找外包合作")
	if !match.Matched || !strings.Contains(match.Reason, "外包") || !strings.Contains(match.Reason, "後端") {
		t.Fatalf("reason=%q does not explain matched cores", match.Reason)
	}
	anchors := NewTopicSignature("推薦 分享", nil)
	if len(anchors.Concepts) != 0 || anchors.Matches("推薦分享") {
		t.Fatal("anchor-only intent must not become a topic")
	}
}
