package viral

import (
	"context"
	"errors"
	"testing"

	"haixun-backend/internal/library/placement"
)

func TestRunDiscover_skipsFailedKeyword(t *testing.T) {
	calls := 0
	crawler := func(ctx context.Context, m placement.MemberContext, keyword string, limit int) ([]placement.DiscoverPost, error) {
		calls++
		if keyword == "bad" {
			return nil, errors.New("api timeout")
		}
		return []placement.DiscoverPost{{
			Text: "轉職面試技巧分享心得", Author: "ok_user", LikeCount: 30, ReplyCount: 4,
			Permalink: "https://www.threads.net/@ok_user/post/1", Source: placement.DiscoverCrawler,
		}}, nil
	}
	member := placement.MemberContext{
		AllowsCrawler:    true,
		BrowserConnected: true,
		SearchSourceMode: placement.SearchSourceCrawler,
	}
	out, err := RunDiscover(context.Background(), DiscoverInput{
		Keywords:    []string{"bad", "轉職"},
		Member:      member,
		Crawler:     crawler,
		MissionScan: true,
	}, nil)
	if err != nil {
		t.Fatalf("expected partial success, got err: %v", err)
	}
	if len(out) != 1 {
		t.Fatalf("expected 1 candidate, got %d", len(out))
	}
	if calls != 2 {
		t.Fatalf("expected 2 keyword attempts, got %d", calls)
	}
}

func TestRunDiscover_missionRelaxedFallbackWithoutVerified(t *testing.T) {
	crawler := func(ctx context.Context, m placement.MemberContext, keyword string, limit int) ([]placement.DiscoverPost, error) {
		return []placement.DiscoverPost{{
			Text: "轉職心得分享", Author: "plain_user", LikeCount: 12, ReplyCount: 2,
			Permalink: "https://www.threads.net/@plain_user/post/2", Source: placement.DiscoverThreadsAPI,
		}}, nil
	}
	member := placement.MemberContext{
		AllowsCrawler:    true,
		BrowserConnected: true,
		SearchSourceMode: placement.SearchSourceCrawler,
	}
	out, err := RunDiscover(context.Background(), DiscoverInput{
		Keywords:    []string{"轉職"},
		Member:      member,
		Crawler:     crawler,
		MissionScan: true,
	}, nil)
	if err != nil {
		t.Fatalf("unexpected err: %v", err)
	}
	if len(out) != 1 {
		t.Fatalf("expected relaxed fallback candidate, got %d", len(out))
	}
	if out[0].AuthorVerified {
		t.Fatal("verified should remain false when API omits it")
	}
}

func TestRunDiscover_missionFiltersOffTopicCrawlerDrift(t *testing.T) {
	crawler := func(ctx context.Context, m placement.MemberContext, keyword string, limit int) ([]placement.DiscoverPost, error) {
		return []placement.DiscoverPost{
			{
				Text:       "毛小孩飲食心得分享，最近很多人問罐罐怎麼挑",
				Author:     "pet_user",
				LikeCount:  200,
				ReplyCount: 40,
				Permalink:  "https://www.threads.net/@pet_user/post/pet",
				Source:     placement.DiscoverCrawler,
			},
			{
				Text:       "備孕精蟲品質心得分享：作息、壓力和檢查報告怎麼一起看",
				Author:     "fertility_user",
				LikeCount:  26,
				ReplyCount: 6,
				Permalink:  "https://www.threads.net/@fertility_user/post/quality",
				Source:     placement.DiscoverCrawler,
			},
		}, nil
	}
	member := placement.MemberContext{
		AllowsCrawler:    true,
		BrowserConnected: true,
		SearchSourceMode: placement.SearchSourceCrawler,
	}
	out, err := RunDiscover(context.Background(), DiscoverInput{
		Keywords:    []string{"精蟲品質"},
		SeedQuery:   "精蟲品質",
		Label:       "備孕內容",
		TopicHints:  []string{"備孕", "精蟲品質"},
		Member:      member,
		Crawler:     crawler,
		MissionScan: true,
	}, nil)
	if err != nil {
		t.Fatalf("unexpected err: %v", err)
	}
	if len(out) != 1 {
		t.Fatalf("expected only topic-matched candidate, got %d", len(out))
	}
	if out[0].Author != "fertility_user" {
		t.Fatalf("expected fertility candidate, got %q", out[0].Author)
	}
}
