package training

import (
	"testing"

	"github.com/google/uuid"
)

// =============================================================================
// buildContentPrompt Tests
// =============================================================================

func TestBuildContentPrompt_ContainsModuleCode(t *testing.T) {
	module := TrainingModule{
		ModuleCode:      "CP-TRAIN-001",
		Title:           "DSGVO Grundlagen",
		Description:     "Basis-Schulung",
		RegulationArea:  RegulationDSGVO,
		DurationMinutes: 30,
	}

	prompt := buildContentPrompt(module, "de")

	if !containsSubstring(prompt, "CP-TRAIN-001") {
		t.Error("Prompt should contain module code")
	}
}

func TestBuildContentPrompt_ContainsTitle(t *testing.T) {
	module := TrainingModule{
		ModuleCode:      "CP-001",
		Title:           "DSGVO Grundlagen",
		RegulationArea:  RegulationDSGVO,
		DurationMinutes: 30,
	}

	prompt := buildContentPrompt(module, "de")

	if !containsSubstring(prompt, "DSGVO Grundlagen") {
		t.Error("Prompt should contain module title")
	}
}

func TestBuildContentPrompt_ContainsRegulationLabel(t *testing.T) {
	tests := []struct {
		name     string
		area     RegulationArea
		expected string
	}{
		{"DSGVO", RegulationDSGVO, "Datenschutz-Grundverordnung"},
		{"NIS2", RegulationNIS2, "NIS-2-Richtlinie"},
		{"ISO27001", RegulationISO27001, "ISO 27001"},
		{"AIAct", RegulationAIAct, "AI Act"},
		{"GeschGehG", RegulationGeschGehG, "Geschaeftsgeheimnisgesetz"},
		{"HinSchG", RegulationHinSchG, "Hinweisgeberschutzgesetz"},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			module := TrainingModule{
				ModuleCode:      "CP-001",
				Title:           "Test Module",
				RegulationArea:  tt.area,
				DurationMinutes: 30,
			}

			prompt := buildContentPrompt(module, "de")

			if !containsSubstring(prompt, tt.expected) {
				t.Errorf("Prompt should contain regulation label '%s' for area '%s'", tt.expected, tt.area)
			}
		})
	}
}

func TestBuildContentPrompt_ContainsDuration(t *testing.T) {
	module := TrainingModule{
		ModuleCode:      "CP-001",
		Title:           "Test",
		RegulationArea:  RegulationDSGVO,
		DurationMinutes: 45,
	}

	prompt := buildContentPrompt(module, "de")

	if !containsSubstring(prompt, "45 Minuten") {
		t.Error("Prompt should contain duration in minutes")
	}
}

func TestBuildContentPrompt_UnknownRegulationArea(t *testing.T) {
	module := TrainingModule{
		ModuleCode:      "CP-001",
		Title:           "Test",
		RegulationArea:  RegulationArea("custom_regulation"),
		DurationMinutes: 30,
	}

	prompt := buildContentPrompt(module, "de")

	if !containsSubstring(prompt, "custom_regulation") {
		t.Error("Unknown regulation area should fall back to raw string")
	}
}

// =============================================================================
// buildQuizPrompt Tests
// =============================================================================

func TestBuildQuizPrompt_ContainsQuestionCount(t *testing.T) {
	module := TrainingModule{
		ModuleCode:     "CP-001",
		Title:          "Test Module",
		RegulationArea: RegulationDSGVO,
	}

	prompt := buildQuizPrompt(module, "", 10)

	if !containsSubstring(prompt, "10") {
		t.Error("Quiz prompt should contain question count")
	}
}

func TestBuildQuizPrompt_ContainsContentContext(t *testing.T) {
	module := TrainingModule{
		ModuleCode:     "CP-001",
		Title:          "Test",
		RegulationArea: RegulationDSGVO,
	}

	prompt := buildQuizPrompt(module, "This is the module content about DSGVO.", 5)

	if !containsSubstring(prompt, "This is the module content about DSGVO.") {
		t.Error("Quiz prompt should include content context")
	}
}

func TestBuildQuizPrompt_TruncatesLongContent(t *testing.T) {
	module := TrainingModule{
		ModuleCode:     "CP-001",
		Title:          "Test",
		RegulationArea: RegulationDSGVO,
	}

	// Create content longer than 3000 chars
	longContent := ""
	for i := 0; i < 400; i++ {
		longContent += "ABCDEFGHIJ" // 10 chars * 400 = 4000 chars
	}

	prompt := buildQuizPrompt(module, longContent, 5)

	if containsSubstring(prompt, longContent) {
		t.Error("Quiz prompt should truncate content longer than 3000 chars")
	}
	if !containsSubstring(prompt, "...") {
		t.Error("Truncated content should end with '...'")
	}
}

func TestBuildQuizPrompt_EmptyContent(t *testing.T) {
	module := TrainingModule{
		ModuleCode:     "CP-001",
		Title:          "Test",
		RegulationArea: RegulationDSGVO,
	}

	prompt := buildQuizPrompt(module, "", 5)

	if containsSubstring(prompt, "Schulungsinhalt als Kontext") {
		t.Error("Empty content should not add context section")
	}
}

// =============================================================================
// parseQuizResponse Tests
// =============================================================================

func TestParseQuizResponse_ValidJSON(t *testing.T) {
	moduleID := uuid.New()
	response := `[
		{
			"question": "Was ist die DSGVO?",
			"options": ["EU-Verordnung", "Bundesgesetz", "Landesgesetz", "Internationale Konvention"],
			"correct_index": 0,
			"explanation": "Die DSGVO ist eine EU-Verordnung.",
			"difficulty": "easy"
		}
	]`

	questions, err := parseQuizResponse(response, moduleID)
	if err != nil {
		t.Fatalf("Expected no error, got %v", err)
	}
	if len(questions) != 1 {
		t.Fatalf("Expected 1 question, got %d", len(questions))
	}
	if questions[0].Question != "Was ist die DSGVO?" {
		t.Errorf("Expected question text, got '%s'", questions[0].Question)
	}
	if questions[0].CorrectIndex != 0 {
		t.Errorf("Expected correct_index 0, got %d", questions[0].CorrectIndex)
	}
	if questions[0].Difficulty != DifficultyEasy {
		t.Errorf("Expected difficulty 'easy', got '%s'", questions[0].Difficulty)
	}
	if questions[0].ModuleID != moduleID {
		t.Error("Module ID should be set on parsed question")
	}
	if !questions[0].IsActive {
		t.Error("Parsed questions should be active by default")
	}
}

func TestParseQuizResponse_InvalidJSON(t *testing.T) {
	moduleID := uuid.New()
	_, err := parseQuizResponse("not valid json at all", moduleID)
	if err == nil {
		t.Error("Expected error for invalid JSON")
	}
}

func TestParseQuizResponse_JSONWithSurroundingText(t *testing.T) {
	moduleID := uuid.New()
	response := `Here are the questions:
[
	{
		"question": "Test?",
		"options": ["A", "B", "C", "D"],
		"correct_index": 1,
		"explanation": "B is correct.",
		"difficulty": "medium"
	}
]
I hope these are helpful!`

	questions, err := parseQuizResponse(response, moduleID)
	if err != nil {
		t.Fatalf("Expected no error, got %v", err)
	}
	if len(questions) != 1 {
		t.Fatalf("Expected 1 question, got %d", len(questions))
	}
}

func TestParseQuizResponse_SkipsMalformedOptions(t *testing.T) {
	moduleID := uuid.New()
	response := `[
		{
			"question": "Good question?",
			"options": ["A", "B", "C", "D"],
			"correct_index": 0,
			"explanation": "A is correct.",
			"difficulty": "easy"
		},
		{
			"question": "Bad question?",
			"options": ["A", "B"],
			"correct_index": 0,
			"explanation": "Only 2 options.",
			"difficulty": "easy"
		}
	]`

	questions, err := parseQuizResponse(response, moduleID)
	if err != nil {
		t.Fatalf("Expected no error, got %v", err)
	}
	if len(questions) != 1 {
		t.Errorf("Expected 1 valid question (malformed should be skipped), got %d", len(questions))
	}
}

func TestParseQuizResponse_SkipsInvalidCorrectIndex(t *testing.T) {
	moduleID := uuid.New()
	response := `[
		{
			"question": "Bad index?",
			"options": ["A", "B", "C", "D"],
			"correct_index": 5,
			"explanation": "Index out of range.",
			"difficulty": "medium"
		}
	]`

	questions, err := parseQuizResponse(response, moduleID)
	if err != nil {
		t.Fatalf("Expected no error, got %v", err)
	}
	if len(questions) != 0 {
		t.Errorf("Expected 0 questions (invalid index should be skipped), got %d", len(questions))
	}
}

func TestParseQuizResponse_NegativeCorrectIndex(t *testing.T) {
	moduleID := uuid.New()
	response := `[
		{
			"question": "Negative index?",
			"options": ["A", "B", "C", "D"],
			"correct_index": -1,
			"explanation": "Negative index.",
			"difficulty": "easy"
		}
	]`

	questions, err := parseQuizResponse(response, moduleID)
	if err != nil {
		t.Fatalf("Expected no error, got %v", err)
	}
	if len(questions) != 0 {
		t.Errorf("Expected 0 questions (negative index should be skipped), got %d", len(questions))
	}
}

func TestParseQuizResponse_DefaultsDifficultyToMedium(t *testing.T) {
	moduleID := uuid.New()
	response := `[
		{
			"question": "Test?",
			"options": ["A", "B", "C", "D"],
			"correct_index": 0,
			"explanation": "A is correct.",
			"difficulty": "unknown_difficulty"
		}
	]`

	questions, err := parseQuizResponse(response, moduleID)
	if err != nil {
		t.Fatalf("Expected no error, got %v", err)
	}
	if len(questions) != 1 {
		t.Fatalf("Expected 1 question, got %d", len(questions))
	}
	if questions[0].Difficulty != DifficultyMedium {
		t.Errorf("Expected difficulty to default to 'medium', got '%s'", questions[0].Difficulty)
	}
}

func TestParseQuizResponse_MultipleQuestions(t *testing.T) {
	moduleID := uuid.New()
	response := `[
		{"question":"Q1?","options":["A","B","C","D"],"correct_index":0,"explanation":"","difficulty":"easy"},
		{"question":"Q2?","options":["A","B","C","D"],"correct_index":1,"explanation":"","difficulty":"medium"},
		{"question":"Q3?","options":["A","B","C","D"],"correct_index":2,"explanation":"","difficulty":"hard"}
	]`

	questions, err := parseQuizResponse(response, moduleID)
	if err != nil {
		t.Fatalf("Expected no error, got %v", err)
	}
	if len(questions) != 3 {
		t.Errorf("Expected 3 questions, got %d", len(questions))
	}
}

func TestParseQuizResponse_EmptyArray(t *testing.T) {
	moduleID := uuid.New()
	questions, err := parseQuizResponse("[]", moduleID)
	if err != nil {
		t.Fatalf("Expected no error, got %v", err)
	}
	if len(questions) != 0 {
		t.Errorf("Expected 0 questions, got %d", len(questions))
	}
}

// =============================================================================
// truncateText Tests
// =============================================================================

func TestTruncateText_ShortText(t *testing.T) {
	result := truncateText("hello", 100)
	if result != "hello" {
		t.Errorf("Short text should not be truncated, got '%s'", result)
	}
}

func TestTruncateText_ExactLength(t *testing.T) {
	result := truncateText("12345", 5)
	if result != "12345" {
		t.Errorf("Text at exact max length should not be truncated, got '%s'", result)
	}
}

func TestTruncateText_LongText(t *testing.T) {
	result := truncateText("1234567890", 5)
	if result != "12345..." {
		t.Errorf("Expected '12345...', got '%s'", result)
	}
}

func TestTruncateText_EmptyString(t *testing.T) {
	result := truncateText("", 10)
	if result != "" {
		t.Errorf("Empty string should remain empty, got '%s'", result)
	}
}

// =============================================================================
// System Prompt Tests
// =============================================================================

func TestGetContentSystemPrompt_German(t *testing.T) {
	prompt := getContentSystemPrompt("de")
	if !containsSubstring(prompt, "Compliance-Schulungsinhalte") {
		t.Error("German system prompt should mention Compliance-Schulungsinhalte")
	}
	if !containsSubstring(prompt, "Markdown") {
		t.Error("System prompt should mention Markdown format")
	}
}

func TestGetContentSystemPrompt_English(t *testing.T) {
	prompt := getContentSystemPrompt("en")
	if !containsSubstring(prompt, "compliance training content") {
		t.Error("English system prompt should mention compliance training content")
	}
}

func TestGetQuizSystemPrompt_ContainsJSONFormat(t *testing.T) {
	prompt := getQuizSystemPrompt()
	if !containsSubstring(prompt, "JSON") {
		t.Error("Quiz system prompt should mention JSON format")
	}
	if !containsSubstring(prompt, "correct_index") {
		t.Error("Quiz system prompt should show correct_index field")
	}
}

// =============================================================================
// buildBlockContentPrompt Tests
// =============================================================================

func TestBuildBlockContentPrompt_ContainsModuleInfo(t *testing.T) {
	module := TrainingModule{
		ModuleCode:      "BLK-AUTH-001",
		Title:           "Authentication Controls",
		DurationMinutes: 45,
	}
	controls := []CanonicalControlSummary{
		{
			ControlID:  "AUTH-001",
			Title:      "Multi-Factor Authentication",
			Objective:  "Ensure MFA is enabled",
			Requirements: []string{"Enable MFA for all users"},
		},
	}

	prompt := buildBlockContentPrompt(module, controls, "de")

	if !containsSubstring(prompt, "BLK-AUTH-001") {
		t.Error("Block prompt should contain module code")
	}
	if !containsSubstring(prompt, "Authentication Controls") {
		t.Error("Block prompt should contain module title")
	}
	if !containsSubstring(prompt, "45 Minuten") {
		t.Error("Block prompt should contain duration")
	}
}

func TestBuildBlockContentPrompt_ContainsControlDetails(t *testing.T) {
	module := TrainingModule{
		ModuleCode:      "BLK-001",
		Title:           "Test",
		DurationMinutes: 30,
	}
	controls := []CanonicalControlSummary{
		{
			ControlID:    "CTRL-001",
			Title:        "Test Control",
			Objective:    "Test objective",
			Requirements: []string{"Req 1", "Req 2"},
		},
	}

	prompt := buildBlockContentPrompt(module, controls, "de")

	if !containsSubstring(prompt, "CTRL-001") {
		t.Error("Prompt should contain control ID")
	}
	if !containsSubstring(prompt, "Test Control") {
		t.Error("Prompt should contain control title")
	}
	if !containsSubstring(prompt, "Test objective") {
		t.Error("Prompt should contain control objective")
	}
	if !containsSubstring(prompt, "Req 1") {
		t.Error("Prompt should contain control requirements")
	}
}

func TestBuildBlockContentPrompt_EnglishVersion(t *testing.T) {
	module := TrainingModule{
		ModuleCode:      "BLK-001",
		Title:           "Test",
		DurationMinutes: 30,
	}
	controls := []CanonicalControlSummary{}

	prompt := buildBlockContentPrompt(module, controls, "en")

	if !containsSubstring(prompt, "Create training material") {
		t.Error("English prompt should use English text")
	}
}

func TestBuildBlockContentPrompt_MultipleControls(t *testing.T) {
	module := TrainingModule{
		ModuleCode:      "BLK-001",
		Title:           "Test",
		DurationMinutes: 30,
	}
	controls := []CanonicalControlSummary{
		{ControlID: "CTRL-001", Title: "First Control", Objective: "Obj 1"},
		{ControlID: "CTRL-002", Title: "Second Control", Objective: "Obj 2"},
		{ControlID: "CTRL-003", Title: "Third Control", Objective: "Obj 3"},
	}

	prompt := buildBlockContentPrompt(module, controls, "de")

	if !containsSubstring(prompt, "3 Sicherheits-Controls") {
		t.Error("Prompt should mention the count of controls")
	}
	if !containsSubstring(prompt, "Control 1") {
		t.Error("Prompt should number controls")
	}
	if !containsSubstring(prompt, "Control 3") {
		t.Error("Prompt should include all controls")
	}
}

// =============================================================================
// Helpers
// =============================================================================

func containsSubstring(s, substr string) bool {
	return len(s) >= len(substr) && searchSubstring(s, substr)
}

func searchSubstring(s, substr string) bool {
	if len(substr) == 0 {
		return true
	}
	for i := 0; i <= len(s)-len(substr); i++ {
		if s[i:i+len(substr)] == substr {
			return true
		}
	}
	return false
}
