package worker

import "testing"

func TestBuildFixedSegmentsUsesFiveToFifteenSeconds(t *testing.T) {
	for _, duration := range []float64{5, 15, 19, 31, 33, 39, 45, 46, 121.4} {
		segments := buildFixedSegments(duration)
		if len(segments) == 0 {
			t.Fatalf("duration %.1f returned no segments", duration)
		}
		for _, segment := range segments {
			length := segment.End - segment.Start
			if length < 5 || length > 15.0001 {
				t.Fatalf("duration %.1f produced %.3f second segment", duration, length)
			}
		}
		if difference := segments[len(segments)-1].End - duration; difference < -0.001 || difference > 0.001 {
			t.Fatalf("duration %.1f ends at %.3f", duration, segments[len(segments)-1].End)
		}
	}
}

func TestNormalizeAnalysisDurationUsesBoundaryTolerance(t *testing.T) {
	tests := []struct {
		input float64
		want  float64
	}{
		{input: 4.01, want: 5},
		{input: 4.999, want: 5},
		{input: 5, want: 5},
		{input: 15, want: 15},
		{input: 15.069002, want: 15},
		{input: 15.999, want: 15},
		{input: 16, want: 16},
	}
	for _, test := range tests {
		if got := normalizeAnalysisDuration(test.input); got != test.want {
			t.Fatalf("normalizeAnalysisDuration(%f) = %f, want %f", test.input, got, test.want)
		}
	}
	segments := buildFixedSegments(normalizeAnalysisDuration(15.069002))
	if len(segments) != 1 || segments[0].End != 15 {
		t.Fatalf("15.069002 seconds produced %#v, want one 15 second segment", segments)
	}
}

func TestBuildFixedSegmentsRedistributesShortTail(t *testing.T) {
	tests := []struct {
		duration float64
		want     []float64
	}{
		{duration: 33, want: []float64{15, 9, 9}},
		{duration: 39, want: []float64{15, 15, 9}},
	}
	for _, test := range tests {
		segments := buildFixedSegments(test.duration)
		if len(segments) != len(test.want) {
			t.Fatalf("duration %.1f produced %d segments, want %d", test.duration, len(segments), len(test.want))
		}
		for index, segment := range segments {
			if got := segment.End - segment.Start; got != test.want[index] {
				t.Fatalf("duration %.1f segment %d = %.1f, want %.1f", test.duration, index+1, got, test.want[index])
			}
		}
	}
}

func TestFrameTimestampsPreserveBoundariesAndLimit(t *testing.T) {
	segment := fixedSegment{Index: 1, Start: 10, End: 23}
	frames := frameTimestamps(segment)
	if len(frames) > 16 {
		t.Fatalf("returned %d frames, want at most 16", len(frames))
	}
	if frames[0] > 10.1 || frames[len(frames)-1] < 22.9 {
		t.Fatalf("boundaries not preserved: first %.3f last %.3f", frames[0], frames[len(frames)-1])
	}
}

func TestFrameRetryTimestampMovesBoundarySamplesIntoSegment(t *testing.T) {
	segment := fixedSegment{Index: 9, Start: 113.31, End: 121.62}
	if got, ok := frameRetryTimestamp(segment, 121.57); !ok || got != 121.07 {
		t.Fatalf("end retry = %.3f, %v; want 121.070, true", got, ok)
	}
	if got, ok := frameRetryTimestamp(segment, 113.36); !ok || got != 113.86 {
		t.Fatalf("start retry = %.3f, %v; want 113.860, true", got, ok)
	}
}

func TestMentionAssetsSkipsDialogue(t *testing.T) {
	tests := []struct {
		name   string
		prompt string
		want   string
	}{
		{
			name:   "Chinese quotes and all asset types",
			prompt: "Grace走进古堡大厅，把青铜钥匙放在桌上，说：“Ethan，去古堡大厅找青铜钥匙和神秘徽记。”神秘徽记微微发光。",
			want:   "@Grace走进@古堡大厅，把@青铜钥匙放在桌上，说：“Ethan，去古堡大厅找青铜钥匙和神秘徽记。”@神秘徽记微微发光。",
		},
		{
			name:   "English quotes and existing mention",
			prompt: `@Grace says: "Ethan, take the Key marked \"Grace\"." Ethan nods beside Castle.`,
			want:   `@Grace says: "Ethan, take the Key marked \"Grace\"." @Ethan nods beside @Castle.`,
		},
	}
	names := []string{"Grace", "Ethan", "古堡大厅", "青铜钥匙", "神秘徽记", "Key", "Castle"}
	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			if got := mentionAssets(test.prompt, names); got != test.want {
				t.Fatalf("mentionAssets() = %q, want %q", got, test.want)
			}
		})
	}
}

func TestMentionAssetsUsesKnownAssetsAndPrefersLongerNames(t *testing.T) {
	names := []string{"지우", "지우의 아버지", "도현", "婚礼殿堂"}
	prompt := "新娘지우走进婚礼殿堂，지우의 아버지看向도현，说：“지우和도현已经到了。”"
	want := "新娘@지우走进@婚礼殿堂，@지우의 아버지看向@도현，说：“지우和도현已经到了。”"
	got := mentionAssets(prompt, names)
	if got != want {
		t.Fatalf("mentionAssets() = %q, want %q", got, want)
	}
	mentioned := mentionedAssetNames(got, names)
	wantMentioned := []string{"지우", "婚礼殿堂", "지우의 아버지", "도현"}
	if len(mentioned) != len(wantMentioned) {
		t.Fatalf("mentionedAssetNames() = %#v, want %#v", mentioned, wantMentioned)
	}
	for index := range wantMentioned {
		if mentioned[index] != wantMentioned[index] {
			t.Fatalf("mentionedAssetNames() = %#v, want %#v", mentioned, wantMentioned)
		}
	}
}

func TestParseSubtitle(t *testing.T) {
	items := parseSubtitle("1\n00:00:01.000 --> 00:00:02.500\n第一句\n\n2\n00:00:03,000 --> 00:00:04,000\n2025年，第二句")
	if len(items) != 2 || items[0].Text != "第一句" || items[1].Text != "2025年，第二句" {
		t.Fatalf("unexpected subtitles: %#v", items)
	}
}
