package training

import (
	"encoding/json"
	"testing"
)

// =============================================================================
// parseNarratorScript Tests
// =============================================================================

func TestParseNarratorScript_ValidJSON(t *testing.T) {
	input := `{
		"title": "DSGVO Grundlagen",
		"intro": "Hallo, ich bin Ihr AI Teacher.",
		"sections": [
			{
				"heading": "Einfuehrung",
				"narrator_text": "Willkommen zur Schulung ueber die DSGVO.",
				"bullet_points": ["Punkt 1", "Punkt 2"],
				"transition": "Bevor wir fortfahren...",
				"checkpoint": {
					"title": "Checkpoint 1",
					"questions": [
						{
							"question": "Was ist die DSGVO?",
							"options": ["EU-Verordnung", "Bundesgesetz", "Landesgesetz", "Internationale Konvention"],
							"correct_index": 0,
							"explanation": "Die DSGVO ist eine EU-Verordnung."
						}
					]
				}
			}
		],
		"outro": "Vielen Dank fuer Ihre Aufmerksamkeit.",
		"total_duration_estimate": 600
	}`

	script, err := parseNarratorScript(input)
	if err != nil {
		t.Fatalf("Expected no error, got %v", err)
	}

	if script.Title != "DSGVO Grundlagen" {
		t.Errorf("Expected title 'DSGVO Grundlagen', got '%s'", script.Title)
	}
	if script.Intro != "Hallo, ich bin Ihr AI Teacher." {
		t.Errorf("Expected intro text, got '%s'", script.Intro)
	}
	if len(script.Sections) != 1 {
		t.Fatalf("Expected 1 section, got %d", len(script.Sections))
	}
	if script.Sections[0].Heading != "Einfuehrung" {
		t.Errorf("Expected heading 'Einfuehrung', got '%s'", script.Sections[0].Heading)
	}
	if script.Sections[0].Checkpoint == nil {
		t.Fatal("Expected checkpoint, got nil")
	}
	if len(script.Sections[0].Checkpoint.Questions) != 1 {
		t.Fatalf("Expected 1 question, got %d", len(script.Sections[0].Checkpoint.Questions))
	}
	if script.Sections[0].Checkpoint.Questions[0].CorrectIndex != 0 {
		t.Errorf("Expected correct_index 0, got %d", script.Sections[0].Checkpoint.Questions[0].CorrectIndex)
	}
	if script.Outro != "Vielen Dank fuer Ihre Aufmerksamkeit." {
		t.Errorf("Expected outro text, got '%s'", script.Outro)
	}
	if script.TotalDurationEstimate != 600 {
		t.Errorf("Expected 600 seconds estimate, got %d", script.TotalDurationEstimate)
	}
}

func TestParseNarratorScript_WithSurroundingText(t *testing.T) {
	input := `Here is the narrator script:
	{
		"title": "NIS-2 Schulung",
		"intro": "Willkommen",
		"sections": [
			{
				"heading": "Abschnitt 1",
				"narrator_text": "Text hier.",
				"bullet_points": ["BP1"],
				"transition": "Weiter"
			}
		],
		"outro": "Ende",
		"total_duration_estimate": 300
	}
	I hope this helps!`

	script, err := parseNarratorScript(input)
	if err != nil {
		t.Fatalf("Expected no error, got %v", err)
	}
	if script.Title != "NIS-2 Schulung" {
		t.Errorf("Expected title 'NIS-2 Schulung', got '%s'", script.Title)
	}
}

func TestParseNarratorScript_InvalidJSON(t *testing.T) {
	_, err := parseNarratorScript("not valid json")
	if err == nil {
		t.Error("Expected error for invalid JSON")
	}
}

func TestParseNarratorScript_NoSections(t *testing.T) {
	input := `{"title": "Test", "intro": "Hi", "sections": [], "outro": "Bye", "total_duration_estimate": 0}`
	_, err := parseNarratorScript(input)
	if err == nil {
		t.Error("Expected error for empty sections")
	}
}

func TestParseNarratorScript_NoJSON(t *testing.T) {
	_, err := parseNarratorScript("Just plain text without any JSON")
	if err == nil {
		t.Error("Expected error when no JSON object found")
	}
}

func TestParseNarratorScript_SectionWithoutCheckpoint(t *testing.T) {
	input := `{
		"title": "Test",
		"intro": "Hi",
		"sections": [
			{
				"heading": "Section 1",
				"narrator_text": "Some text",
				"bullet_points": ["P1"],
				"transition": "Next"
			}
		],
		"outro": "Bye",
		"total_duration_estimate": 180
	}`

	script, err := parseNarratorScript(input)
	if err != nil {
		t.Fatalf("Expected no error, got %v", err)
	}
	if script.Sections[0].Checkpoint != nil {
		t.Error("Section without checkpoint definition should have nil Checkpoint")
	}
}

func TestParseNarratorScript_MultipleSectionsWithCheckpoints(t *testing.T) {
	input := `{
		"title": "Multi-Section",
		"intro": "Start",
		"sections": [
			{
				"heading": "S1",
				"narrator_text": "Text 1",
				"bullet_points": [],
				"transition": "T1",
				"checkpoint": {
					"title": "CP1",
					"questions": [
						{"question": "Q1?", "options": ["A", "B", "C", "D"], "correct_index": 0, "explanation": "E1"},
						{"question": "Q2?", "options": ["A", "B", "C", "D"], "correct_index": 1, "explanation": "E2"}
					]
				}
			},
			{
				"heading": "S2",
				"narrator_text": "Text 2",
				"bullet_points": ["BP"],
				"transition": "T2",
				"checkpoint": {
					"title": "CP2",
					"questions": [
						{"question": "Q3?", "options": ["A", "B", "C", "D"], "correct_index": 2, "explanation": "E3"}
					]
				}
			},
			{
				"heading": "S3",
				"narrator_text": "Text 3",
				"bullet_points": [],
				"transition": "T3"
			}
		],
		"outro": "End",
		"total_duration_estimate": 900
	}`

	script, err := parseNarratorScript(input)
	if err != nil {
		t.Fatalf("Expected no error, got %v", err)
	}
	if len(script.Sections) != 3 {
		t.Fatalf("Expected 3 sections, got %d", len(script.Sections))
	}
	if script.Sections[0].Checkpoint == nil {
		t.Error("Section 0 should have a checkpoint")
	}
	if len(script.Sections[0].Checkpoint.Questions) != 2 {
		t.Errorf("Section 0 checkpoint should have 2 questions, got %d", len(script.Sections[0].Checkpoint.Questions))
	}
	if script.Sections[1].Checkpoint == nil {
		t.Error("Section 1 should have a checkpoint")
	}
	if script.Sections[2].Checkpoint != nil {
		t.Error("Section 2 should not have a checkpoint")
	}
}

// =============================================================================
// countCheckpoints Tests
// =============================================================================

func TestCountCheckpoints_WithCheckpoints(t *testing.T) {
	script := &NarratorScript{
		Sections: []NarratorSection{
			{Checkpoint: &CheckpointDefinition{Title: "CP1"}},
			{Checkpoint: nil},
			{Checkpoint: &CheckpointDefinition{Title: "CP3"}},
		},
	}

	count := countCheckpoints(script)
	if count != 2 {
		t.Errorf("Expected 2 checkpoints, got %d", count)
	}
}

func TestCountCheckpoints_NoCheckpoints(t *testing.T) {
	script := &NarratorScript{
		Sections: []NarratorSection{
			{Heading: "S1"},
			{Heading: "S2"},
		},
	}

	count := countCheckpoints(script)
	if count != 0 {
		t.Errorf("Expected 0 checkpoints, got %d", count)
	}
}

func TestCountCheckpoints_EmptySections(t *testing.T) {
	script := &NarratorScript{}
	count := countCheckpoints(script)
	if count != 0 {
		t.Errorf("Expected 0 checkpoints, got %d", count)
	}
}

// =============================================================================
// NarratorScript JSON Serialization Tests
// =============================================================================

func TestNarratorScript_JSONRoundTrip(t *testing.T) {
	original := NarratorScript{
		Title: "Test",
		Intro: "Hello",
		Sections: []NarratorSection{
			{
				Heading:      "H1",
				NarratorText: "NT1",
				BulletPoints: []string{"BP1"},
				Transition:   "T1",
				Checkpoint: &CheckpointDefinition{
					Title: "CP1",
					Questions: []CheckpointQuestion{
						{
							Question:     "Q?",
							Options:      []string{"A", "B", "C", "D"},
							CorrectIndex: 2,
							Explanation:  "C is correct",
						},
					},
				},
			},
		},
		Outro:                 "Bye",
		TotalDurationEstimate: 600,
	}

	data, err := json.Marshal(original)
	if err != nil {
		t.Fatalf("Marshal failed: %v", err)
	}

	var decoded NarratorScript
	if err := json.Unmarshal(data, &decoded); err != nil {
		t.Fatalf("Unmarshal failed: %v", err)
	}

	if decoded.Title != original.Title {
		t.Errorf("Title mismatch: %s != %s", decoded.Title, original.Title)
	}
	if len(decoded.Sections) != 1 {
		t.Fatalf("Expected 1 section, got %d", len(decoded.Sections))
	}
	if decoded.Sections[0].Checkpoint == nil {
		t.Fatal("Checkpoint should not be nil after round-trip")
	}
	if decoded.Sections[0].Checkpoint.Questions[0].CorrectIndex != 2 {
		t.Errorf("CorrectIndex mismatch: got %d", decoded.Sections[0].Checkpoint.Questions[0].CorrectIndex)
	}
}

// =============================================================================
// InteractiveVideoManifest Tests
// =============================================================================

func TestInteractiveVideoManifest_JSON(t *testing.T) {
	manifest := InteractiveVideoManifest{
		StreamURL: "https://example.com/video.mp4",
		Checkpoints: []CheckpointManifestEntry{
			{
				Index:            0,
				Title:            "CP1",
				TimestampSeconds: 180.5,
				Questions: []CheckpointQuestion{
					{
						Question:     "Q?",
						Options:      []string{"A", "B", "C", "D"},
						CorrectIndex: 1,
						Explanation:  "B",
					},
				},
			},
		},
	}

	data, err := json.Marshal(manifest)
	if err != nil {
		t.Fatalf("Marshal failed: %v", err)
	}

	var decoded InteractiveVideoManifest
	if err := json.Unmarshal(data, &decoded); err != nil {
		t.Fatalf("Unmarshal failed: %v", err)
	}

	if len(decoded.Checkpoints) != 1 {
		t.Fatalf("Expected 1 checkpoint, got %d", len(decoded.Checkpoints))
	}
	if decoded.Checkpoints[0].TimestampSeconds != 180.5 {
		t.Errorf("Timestamp mismatch: got %f", decoded.Checkpoints[0].TimestampSeconds)
	}
}

// =============================================================================
// SubmitCheckpointQuizRequest/Response Tests
// =============================================================================

func TestSubmitCheckpointQuizResponse_JSON(t *testing.T) {
	resp := SubmitCheckpointQuizResponse{
		Passed: true,
		Score:  80.0,
		Feedback: []CheckpointQuizFeedback{
			{Question: "Q1?", Correct: true, Explanation: "Correct!"},
			{Question: "Q2?", Correct: false, Explanation: "Wrong answer."},
		},
	}

	data, err := json.Marshal(resp)
	if err != nil {
		t.Fatalf("Marshal failed: %v", err)
	}

	var decoded SubmitCheckpointQuizResponse
	if err := json.Unmarshal(data, &decoded); err != nil {
		t.Fatalf("Unmarshal failed: %v", err)
	}

	if !decoded.Passed {
		t.Error("Expected passed=true")
	}
	if decoded.Score != 80.0 {
		t.Errorf("Expected score 80.0, got %f", decoded.Score)
	}
	if len(decoded.Feedback) != 2 {
		t.Fatalf("Expected 2 feedback items, got %d", len(decoded.Feedback))
	}
	if decoded.Feedback[1].Correct {
		t.Error("Second feedback should be incorrect")
	}
}

// =============================================================================
// narratorSystemPrompt Tests
// =============================================================================

func TestNarratorSystemPrompt_ContainsKeyPhrases(t *testing.T) {
	if !containsSubstring(narratorSystemPrompt, "AI Teacher") {
		t.Error("System prompt should mention AI Teacher")
	}
	if !containsSubstring(narratorSystemPrompt, "Checkpoint") {
		t.Error("System prompt should mention Checkpoint")
	}
	if !containsSubstring(narratorSystemPrompt, "JSON") {
		t.Error("System prompt should mention JSON format")
	}
	if !containsSubstring(narratorSystemPrompt, "correct_index") {
		t.Error("System prompt should mention correct_index")
	}
}

// =============================================================================
// Checkpoint Grading Logic Tests (User Journey: Learner scores quiz)
// =============================================================================

func TestCheckpointGrading_AllCorrect_ScoreIs100(t *testing.T) {
	questions := []CheckpointQuestion{
		{Question: "Q1?", Options: []string{"A", "B", "C", "D"}, CorrectIndex: 0},
		{Question: "Q2?", Options: []string{"A", "B", "C", "D"}, CorrectIndex: 1},
		{Question: "Q3?", Options: []string{"A", "B", "C", "D"}, CorrectIndex: 2},
	}
	answers := []int{0, 1, 2}

	correctCount := 0
	for i, q := range questions {
		if i < len(answers) && answers[i] == q.CorrectIndex {
			correctCount++
		}
	}
	score := float64(correctCount) / float64(len(questions)) * 100
	passed := score >= 70

	if score != 100.0 {
		t.Errorf("Expected score 100, got %f", score)
	}
	if !passed {
		t.Error("Expected passed=true with 100% score")
	}
}

func TestCheckpointGrading_NoneCorrect_ScoreIs0(t *testing.T) {
	questions := []CheckpointQuestion{
		{Question: "Q1?", Options: []string{"A", "B", "C", "D"}, CorrectIndex: 0},
		{Question: "Q2?", Options: []string{"A", "B", "C", "D"}, CorrectIndex: 1},
		{Question: "Q3?", Options: []string{"A", "B", "C", "D"}, CorrectIndex: 2},
	}
	answers := []int{3, 3, 3}

	correctCount := 0
	for i, q := range questions {
		if i < len(answers) && answers[i] == q.CorrectIndex {
			correctCount++
		}
	}
	score := float64(correctCount) / float64(len(questions)) * 100
	passed := score >= 70

	if score != 0.0 {
		t.Errorf("Expected score 0, got %f", score)
	}
	if passed {
		t.Error("Expected passed=false with 0% score")
	}
}

func TestCheckpointGrading_ExactlyAt70Percent_Passes(t *testing.T) {
	// 7 out of 10 correct = 70% — exactly at threshold
	questions := make([]CheckpointQuestion, 10)
	answers := make([]int, 10)
	for i := 0; i < 10; i++ {
		questions[i] = CheckpointQuestion{
			Question: "Q?", Options: []string{"A", "B", "C", "D"}, CorrectIndex: 0,
		}
		if i < 7 {
			answers[i] = 0 // correct
		} else {
			answers[i] = 1 // wrong
		}
	}

	correctCount := 0
	for i, q := range questions {
		if i < len(answers) && answers[i] == q.CorrectIndex {
			correctCount++
		}
	}
	score := float64(correctCount) / float64(len(questions)) * 100
	passed := score >= 70

	if score != 70.0 {
		t.Errorf("Expected score 70, got %f", score)
	}
	if !passed {
		t.Error("Expected passed=true at exactly 70%")
	}
}

func TestCheckpointGrading_JustBelow70Percent_Fails(t *testing.T) {
	// 2 out of 3 correct = 66.67% — below threshold
	questions := []CheckpointQuestion{
		{Question: "Q1?", Options: []string{"A", "B", "C", "D"}, CorrectIndex: 0},
		{Question: "Q2?", Options: []string{"A", "B", "C", "D"}, CorrectIndex: 1},
		{Question: "Q3?", Options: []string{"A", "B", "C", "D"}, CorrectIndex: 2},
	}
	answers := []int{0, 1, 3} // 2 correct, 1 wrong

	correctCount := 0
	for i, q := range questions {
		if i < len(answers) && answers[i] == q.CorrectIndex {
			correctCount++
		}
	}
	score := float64(correctCount) / float64(len(questions)) * 100
	passed := score >= 70

	if passed {
		t.Errorf("Expected passed=false at %.2f%%", score)
	}
}

func TestCheckpointGrading_FewerAnswersThanQuestions_MarksUnansweredWrong(t *testing.T) {
	questions := []CheckpointQuestion{
		{Question: "Q1?", Options: []string{"A", "B", "C", "D"}, CorrectIndex: 0},
		{Question: "Q2?", Options: []string{"A", "B", "C", "D"}, CorrectIndex: 1},
		{Question: "Q3?", Options: []string{"A", "B", "C", "D"}, CorrectIndex: 2},
	}
	answers := []int{0} // Only 1 answer for 3 questions

	correctCount := 0
	for i, q := range questions {
		if i < len(answers) && answers[i] == q.CorrectIndex {
			correctCount++
		}
	}

	if correctCount != 1 {
		t.Errorf("Expected 1 correct, got %d", correctCount)
	}
	score := float64(correctCount) / float64(len(questions)) * 100
	if score > 34 {
		t.Errorf("Expected score ~33.3%%, got %f", score)
	}
}

func TestCheckpointGrading_EmptyAnswers_AllWrong(t *testing.T) {
	questions := []CheckpointQuestion{
		{Question: "Q1?", Options: []string{"A", "B"}, CorrectIndex: 0},
		{Question: "Q2?", Options: []string{"A", "B"}, CorrectIndex: 1},
	}
	answers := []int{}

	correctCount := 0
	for i, q := range questions {
		if i < len(answers) && answers[i] == q.CorrectIndex {
			correctCount++
		}
	}

	if correctCount != 0 {
		t.Errorf("Expected 0 correct with empty answers, got %d", correctCount)
	}
}

// =============================================================================
// Feedback Generation Tests (User Journey: Learner sees feedback)
// =============================================================================

func TestCheckpointFeedback_CorrectAnswerGetsCorrectFlag(t *testing.T) {
	questions := []CheckpointQuestion{
		{Question: "Was ist DSGVO?", Options: []string{"EU-Verordnung", "Bundesgesetz"}, CorrectIndex: 0, Explanation: "EU-Verordnung"},
		{Question: "Wer ist DSB?", Options: []string{"IT-Leiter", "Datenschutzbeauftragter"}, CorrectIndex: 1, Explanation: "DSB Rolle"},
	}
	answers := []int{0, 0} // First correct, second wrong

	feedback := make([]CheckpointQuizFeedback, len(questions))
	for i, q := range questions {
		isCorrect := false
		if i < len(answers) && answers[i] == q.CorrectIndex {
			isCorrect = true
		}
		feedback[i] = CheckpointQuizFeedback{
			Question:    q.Question,
			Correct:     isCorrect,
			Explanation: q.Explanation,
		}
	}

	if !feedback[0].Correct {
		t.Error("First answer should be marked correct")
	}
	if feedback[1].Correct {
		t.Error("Second answer should be marked incorrect")
	}
	if feedback[0].Question != "Was ist DSGVO?" {
		t.Errorf("Unexpected question text: %s", feedback[0].Question)
	}
	if feedback[1].Explanation != "DSB Rolle" {
		t.Errorf("Explanation should be preserved: got %s", feedback[1].Explanation)
	}
}

// =============================================================================
// NarratorScript Pipeline Tests (User Journey: Admin generates video)
// =============================================================================

func TestNarratorScript_SectionCounting(t *testing.T) {
	tests := []struct {
		name            string
		sectionCount    int
		checkpointCount int
	}{
		{"3 sections, all with checkpoints", 3, 3},
		{"4 sections, 2 with checkpoints", 4, 2},
		{"1 section, no checkpoint", 1, 0},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			sections := make([]NarratorSection, tt.sectionCount)
			cpAdded := 0
			for i := 0; i < tt.sectionCount; i++ {
				sections[i] = NarratorSection{
					Heading:      "Section",
					NarratorText: "Text",
					BulletPoints: []string{},
					Transition:   "Next",
				}
				if cpAdded < tt.checkpointCount {
					sections[i].Checkpoint = &CheckpointDefinition{
						Title:     "CP",
						Questions: []CheckpointQuestion{{Question: "Q?", Options: []string{"A", "B"}, CorrectIndex: 0}},
					}
					cpAdded++
				}
			}

			script := &NarratorScript{
				Title:    "Test",
				Intro:    "Hi",
				Sections: sections,
				Outro:    "Bye",
			}

			if len(script.Sections) != tt.sectionCount {
				t.Errorf("Expected %d sections, got %d", tt.sectionCount, len(script.Sections))
			}
			if countCheckpoints(script) != tt.checkpointCount {
				t.Errorf("Expected %d checkpoints, got %d", tt.checkpointCount, countCheckpoints(script))
			}
		})
	}
}

func TestNarratorScript_SectionAudioConversion(t *testing.T) {
	// Verify NarratorSection can be converted to SectionAudio for TTS
	sections := []NarratorSection{
		{Heading: "Einleitung", NarratorText: "Willkommen zur Schulung."},
		{Heading: "Hauptteil", NarratorText: "Hier lernen Sie die Grundlagen."},
	}

	audioSections := make([]SectionAudio, len(sections))
	for i, s := range sections {
		audioSections[i] = SectionAudio{
			Text:    s.NarratorText,
			Heading: s.Heading,
		}
	}

	if len(audioSections) != 2 {
		t.Fatalf("Expected 2 audio sections, got %d", len(audioSections))
	}
	if audioSections[0].Heading != "Einleitung" {
		t.Errorf("Expected heading 'Einleitung', got '%s'", audioSections[0].Heading)
	}
	if audioSections[1].Text != "Hier lernen Sie die Grundlagen." {
		t.Errorf("Unexpected text: '%s'", audioSections[1].Text)
	}
}

// =============================================================================
// InteractiveVideoManifest Progress Tests (User Journey: Learner resumes)
// =============================================================================

func TestManifest_IdentifiesNextUnpassedCheckpoint(t *testing.T) {
	manifest := InteractiveVideoManifest{
		StreamURL: "https://example.com/video.mp4",
		Checkpoints: []CheckpointManifestEntry{
			{Index: 0, Title: "CP1", TimestampSeconds: 180, Progress: &CheckpointProgress{Passed: true}},
			{Index: 1, Title: "CP2", TimestampSeconds: 360, Progress: &CheckpointProgress{Passed: false}},
			{Index: 2, Title: "CP3", TimestampSeconds: 540, Progress: nil},
		},
	}

	var nextUnpassed *CheckpointManifestEntry
	for i := range manifest.Checkpoints {
		cp := &manifest.Checkpoints[i]
		if cp.Progress == nil || !cp.Progress.Passed {
			nextUnpassed = cp
			break
		}
	}

	if nextUnpassed == nil {
		t.Fatal("Expected to find an unpassed checkpoint")
	}
	if nextUnpassed.Index != 1 {
		t.Errorf("Expected next unpassed at index 1, got %d", nextUnpassed.Index)
	}
	if nextUnpassed.Title != "CP2" {
		t.Errorf("Expected CP2, got %s", nextUnpassed.Title)
	}
}

func TestManifest_AllCheckpointsPassed(t *testing.T) {
	manifest := InteractiveVideoManifest{
		Checkpoints: []CheckpointManifestEntry{
			{Index: 0, Progress: &CheckpointProgress{Passed: true}},
			{Index: 1, Progress: &CheckpointProgress{Passed: true}},
		},
	}

	allPassed := true
	for _, cp := range manifest.Checkpoints {
		if cp.Progress == nil || !cp.Progress.Passed {
			allPassed = false
			break
		}
	}

	if !allPassed {
		t.Error("Expected all checkpoints to be passed")
	}
}

func TestManifest_NoCheckpoints_AllPassedIsTrue(t *testing.T) {
	manifest := InteractiveVideoManifest{
		Checkpoints: []CheckpointManifestEntry{},
	}

	allPassed := true
	for _, cp := range manifest.Checkpoints {
		if cp.Progress == nil || !cp.Progress.Passed {
			allPassed = false
			break
		}
	}

	if !allPassed {
		t.Error("Empty checkpoint list should be considered all-passed")
	}
}

func TestManifest_SeekProtection_BlocksSkippingPastUnpassed(t *testing.T) {
	// Simulates seek protection logic from InteractiveVideoPlayer
	checkpoints := []CheckpointManifestEntry{
		{Index: 0, TimestampSeconds: 180, Progress: &CheckpointProgress{Passed: true}},
		{Index: 1, TimestampSeconds: 360, Progress: nil}, // Not yet attempted
		{Index: 2, TimestampSeconds: 540, Progress: nil},
	}

	seekTarget := 500.0 // User tries to seek to 500s

	// Find first unpassed checkpoint
	var firstUnpassed *CheckpointManifestEntry
	for i := range checkpoints {
		if checkpoints[i].Progress == nil || !checkpoints[i].Progress.Passed {
			firstUnpassed = &checkpoints[i]
			break
		}
	}

	blocked := false
	if firstUnpassed != nil && seekTarget > firstUnpassed.TimestampSeconds {
		blocked = true
	}

	if !blocked {
		t.Error("Seek past unpassed checkpoint should be blocked")
	}
	if firstUnpassed.TimestampSeconds != 360 {
		t.Errorf("Expected block at 360s, got %f", firstUnpassed.TimestampSeconds)
	}
}

func TestManifest_SeekProtection_AllowsSeekBeforeFirstUnpassed(t *testing.T) {
	checkpoints := []CheckpointManifestEntry{
		{Index: 0, TimestampSeconds: 180, Progress: &CheckpointProgress{Passed: true}},
		{Index: 1, TimestampSeconds: 360, Progress: nil},
	}

	seekTarget := 200.0 // User seeks to 200s — before unpassed checkpoint at 360s

	var firstUnpassed *CheckpointManifestEntry
	for i := range checkpoints {
		if checkpoints[i].Progress == nil || !checkpoints[i].Progress.Passed {
			firstUnpassed = &checkpoints[i]
			break
		}
	}

	blocked := false
	if firstUnpassed != nil && seekTarget > firstUnpassed.TimestampSeconds {
		blocked = true
	}

	if blocked {
		t.Error("Seek before unpassed checkpoint should be allowed")
	}
}
