package maintenance

import (
	"bamort/database"
	"bamort/models"
	"os"
	"testing"
)

func setupTestEnvironment(t *testing.T) {
	original := os.Getenv("ENVIRONMENT")
	os.Setenv("ENVIRONMENT", "test")
	t.Cleanup(func() {
		if original != "" {
			os.Setenv("ENVIRONMENT", original)
		} else {
			os.Unsetenv("ENVIRONMENT")
		}
	})
}

func TestMigrateSkillCategoriesToRelations(t *testing.T) {
	setupTestEnvironment(t)

	// Reset and setup fresh test database to avoid interference from other tests
	database.ResetTestDB()
	database.SetupTestDB()
	testDB := database.DB

	// Ensure database is valid
	if testDB == nil {
		t.Fatal("Database connection is nil")
	}

	// Create a test source - use unique code to avoid conflicts
	source := models.Source{
		Code:       "TSTMIG1",
		Name:       "Test Migration Source",
		GameSystem: "midgard",
		IsActive:   true,
	}
	if err := testDB.Create(&source).Error; err != nil {
		t.Fatalf("Failed to create test source: %v", err)
	}

	// Create test skills with old-style category/difficulty - use unique names to avoid conflicts
	testSkills := []models.Skill{
		{
			Name:             "TestMigSkill_Schwimmen",
			Category:         "Körper",
			Difficulty:       "leicht",
			GameSystem:       "midgard",
			Initialwert:      12,
			Improvable:       true,
			Bonuseigenschaft: "Gw",
			SourceID:         source.ID,
		},
		{
			Name:             "TestMigSkill_Klettern",
			Category:         "Körper",
			Difficulty:       "normal",
			GameSystem:       "midgard",
			Initialwert:      10,
			Improvable:       true,
			Bonuseigenschaft: "Gw",
			SourceID:         source.ID,
		},
		{
			Name:             "TestMigSkill_LesenSchreiben",
			Category:         "Wissen",
			Difficulty:       "schwer",
			GameSystem:       "midgard",
			Initialwert:      0,
			Improvable:       true,
			Bonuseigenschaft: "In",
			SourceID:         source.ID,
		},
	}

	for i := range testSkills {
		if err := testDB.Create(&testSkills[i]).Error; err != nil {
			t.Fatalf("Failed to create test skill: %v", err)
		}
	}

	// Run migration
	if err := MigrateSkillCategoriesToRelations(testDB); err != nil {
		t.Fatalf("Migration failed: %v", err)
	}

	// Verify migration results
	for _, skill := range testSkills {
		var scds []models.SkillCategoryDifficulty
		err := testDB.Preload("SkillCategory").Preload("SkillDifficulty").
			Where("skill_id = ?", skill.ID).Find(&scds).Error
		if err != nil {
			t.Errorf("Failed to find migrated data for skill %s: %v", skill.Name, err)
			continue
		}

		if len(scds) == 0 {
			t.Errorf("No SkillCategoryDifficulty created for skill %s", skill.Name)
			continue
		}

		scd := scds[0]
		if scd.SkillCategory.Name != skill.Category {
			t.Errorf("Category mismatch for %s: expected %s, got %s",
				skill.Name, skill.Category, scd.SkillCategory.Name)
		}

		if scd.SkillDifficulty.Name != skill.Difficulty {
			t.Errorf("Difficulty mismatch for %s: expected %s, got %s",
				skill.Name, skill.Difficulty, scd.SkillDifficulty.Name)
		}
	}

	// Test idempotency - running migration again should not create duplicates
	if err := MigrateSkillCategoriesToRelations(testDB); err != nil {
		t.Fatalf("Second migration failed: %v", err)
	}

	for _, skill := range testSkills {
		var count int64
		testDB.Model(&models.SkillCategoryDifficulty{}).Where("skill_id = ?", skill.ID).Count(&count)
		if count != 1 {
			t.Errorf("Idempotency check failed for %s: expected 1 record, got %d", skill.Name, count)
		}
	}
}

func TestGetDefaultLearnCost(t *testing.T) {
	tests := []struct {
		difficulty string
		expected   int
	}{
		{"leicht", 5},
		{"easy", 5},
		{"normal", 10},
		{"standard", 10},
		{"schwer", 20},
		{"hard", 20},
		{"sehr schwer", 30},
		{"very hard", 30},
		{"unknown", 10}, // default
	}

	for _, tt := range tests {
		t.Run(tt.difficulty, func(t *testing.T) {
			result := getDefaultLearnCost(tt.difficulty)
			if result != tt.expected {
				t.Errorf("getDefaultLearnCost(%s) = %d, expected %d",
					tt.difficulty, result, tt.expected)
			}
		})
	}
}

func TestMigrateSkillCategoryDifficulty_NoCategory(t *testing.T) {
	setupTestEnvironment(t)

	// Reset and setup fresh test database to avoid interference from other tests
	database.ResetTestDB()
	database.SetupTestDB()
	testDB := database.DB

	// Ensure database is valid
	if testDB == nil {
		t.Fatal("Database connection is nil")
	}

	// Use existing source or create one with a unique code
	var source models.Source
	err := testDB.Where("code = ?", "KOD").First(&source).Error
	if err != nil {
		// Create a test source if KOD doesn't exist
		source = models.Source{
			Code:       "TSTMIG2",
			Name:       "Test Migration Source 2",
			GameSystem: "midgard",
			IsActive:   true,
		}
		if err := testDB.Create(&source).Error; err != nil {
			t.Fatalf("Failed to create test source: %v", err)
		}
	}

	// Create skill without category (should use default) - use unique name
	skill := models.Skill{
		Name:        "TestMigSkill_NoCategory",
		Category:    "", // Empty category
		Difficulty:  "", // Empty difficulty
		GameSystem:  "midgard",
		Initialwert: 10,
		SourceID:    source.ID,
	}
	if err := testDB.Create(&skill).Error; err != nil {
		t.Fatalf("Failed to create test skill: %v", err)
	}

	// Migrate
	if err := migrateSkillCategoryDifficulty(testDB, &skill); err != nil {
		t.Fatalf("Migration failed: %v", err)
	}

	// Verify defaults were used
	var scd models.SkillCategoryDifficulty
	err = testDB.Preload("SkillCategory").Preload("SkillDifficulty").
		Where("skill_id = ?", skill.ID).First(&scd).Error
	if err != nil {
		t.Fatalf("Failed to find migrated data: %v", err)
	}

	if scd.SkillCategory.Name != "Alltag" {
		t.Errorf("Expected default category 'Alltag', got %s", scd.SkillCategory.Name)
	}

	if scd.SkillDifficulty.Name != "normal" {
		t.Errorf("Expected default difficulty 'normal', got %s", scd.SkillDifficulty.Name)
	}
}
