package transfer

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

func setupImportTestEnvironment(t *testing.T) {
	original := os.Getenv("ENVIRONMENT")
	os.Setenv("ENVIRONMENT", "test")
	database.SetupTestDB(true, true)
	models.MigrateStructure()
	t.Cleanup(func() {
		database.ResetTestDB()
		if original == "" {
			os.Unsetenv("ENVIRONMENT")
		} else {
			os.Setenv("ENVIRONMENT", original)
		}
	})
}

func TestImportCharacter(t *testing.T) {
	setupImportTestEnvironment(t)

	// First export character 18
	exportData, err := ExportCharacter(uint(18))
	if err != nil {
		t.Fatalf("Failed to export character: %v", err)
	}

	// Change IDs to simulate import into new system
	originalID := exportData.Character.ID
	exportData.Character.ID = 0 // Reset ID for new character
	exportData.Character.Name = "Imported " + exportData.Character.Name

	// Import the character
	importedCharID, err := ImportCharacter(exportData, 1) // UserID 1
	if err != nil {
		t.Fatalf("ImportCharacter failed: %v", err)
	}

	if importedCharID == 0 {
		t.Error("Expected non-zero character ID after import")
	}

	if importedCharID == originalID {
		t.Error("Imported character should have new ID, not original ID")
	}

	// Verify imported character exists
	var importedChar models.Char
	err = database.DB.Preload("Fertigkeiten").Preload("Zauber").Preload("Waffen").First(&importedChar, importedCharID).Error
	if err != nil {
		t.Fatalf("Failed to load imported character: %v", err)
	}

	// Verify skills were imported
	if len(importedChar.Fertigkeiten) != len(exportData.Character.Fertigkeiten) {
		t.Errorf("Expected %d skills, got %d", len(exportData.Character.Fertigkeiten), len(importedChar.Fertigkeiten))
	}
}

func TestImportCharacterWithExistingGSMData(t *testing.T) {
	setupImportTestEnvironment(t)

	// Export character 18
	exportData, err := ExportCharacter(uint(18))
	if err != nil {
		t.Fatalf("Failed to export character: %v", err)
	}

	// Count existing skills in GSM before import
	var skillCountBefore int64
	database.DB.Model(&models.Skill{}).Count(&skillCountBefore)

	exportData.Character.ID = 0
	exportData.Character.Name = "Test Import"

	// Import character
	_, err = ImportCharacter(exportData, 1)
	if err != nil {
		t.Fatalf("ImportCharacter failed: %v", err)
	}

	// Count skills after - should be same (no duplicates)
	var skillCountAfter int64
	database.DB.Model(&models.Skill{}).Count(&skillCountAfter)

	if skillCountAfter < skillCountBefore {
		t.Error("Skills should not be deleted during import")
	}
}

func TestImportCharacterUpdatesIncompleteGSMData(t *testing.T) {
	setupImportTestEnvironment(t)

	// Create a skill with incomplete data (no description)
	incompleteSkill := models.Skill{
		ID:           1000,
		Name:         "TestSkillIncomplete",
		GameSystem:   "midgard",
		Beschreibung: "",
		Category:     "",
	}
	database.DB.Create(&incompleteSkill)

	// Create export data with complete version of same skill
	exportData := &CharacterExport{
		Character: models.Char{
			BamortBase: models.BamortBase{
				Name: "Test Char",
			},
			Typ:    "Krieger",
			Rasse:  "Mensch",
			Grad:   1,
			UserID: 1,
		},
		GSMSkills: []models.Skill{
			{
				Name:         "TestSkillIncomplete",
				GameSystem:   "midgard",
				Beschreibung: "Complete description",
				Category:     "Alltag",
				Difficulty:   "normal",
			},
		},
	}

	_, err := ImportCharacter(exportData, 1)
	if err != nil {
		t.Fatalf("ImportCharacter failed: %v", err)
	}

	// Verify skill was updated
	var updatedSkill models.Skill
	database.DB.Where("name = ?", "TestSkillIncomplete").First(&updatedSkill)

	if updatedSkill.Beschreibung != "Complete description" {
		t.Error("Expected skill description to be updated")
	}
	if updatedSkill.Category != "Alltag" {
		t.Error("Expected skill category to be updated")
	}
}

func TestImportCharacterSetsSourceIDDefault(t *testing.T) {
	setupImportTestEnvironment(t)

	exportData := &CharacterExport{
		Character: models.Char{
			BamortBase: models.BamortBase{
				Name: "Test Char",
			},
			Typ:    "Krieger",
			Rasse:  "Mensch",
			Grad:   1,
			UserID: 1,
		},
		GSMSkills: []models.Skill{
			{
				Name:       "TestSkill",
				GameSystem: "midgard",
				SourceID:   0, // Should be set to 1
			},
		},
		GSMSpells: []models.Spell{
			{
				Name:       "TestSpell",
				GameSystem: "midgard",
				SourceID:   0, // Should be set to 2
			},
		},
	}

	_, err := ImportCharacter(exportData, 1)
	if err != nil {
		t.Fatalf("ImportCharacter failed: %v", err)
	}

	// Verify skill source_id was set to 1
	var skill models.Skill
	database.DB.Where("name = ?", "TestSkill").First(&skill)
	if skill.SourceID != 1 {
		t.Errorf("Expected skill source_id to be 1, got %d", skill.SourceID)
	}

	// Verify spell source_id was set to 2
	var spell models.Spell
	database.DB.Where("name = ?", "TestSpell").First(&spell)
	if spell.SourceID != 2 {
		t.Errorf("Expected spell source_id to be 2, got %d", spell.SourceID)
	}
}

func TestImportCharacterIncludesAuditLog(t *testing.T) {
	setupImportTestEnvironment(t)

	// Create export data with audit log entries
	exportData := &CharacterExport{
		Character: models.Char{
			BamortBase: models.BamortBase{
				Name: "Test Char",
			},
			Typ:    "Krieger",
			Rasse:  "Mensch",
			Grad:   1,
			UserID: 1,
		},
		AuditLogEntries: []models.AuditLogEntry{
			{
				FieldName:  "experience_points",
				OldValue:   100,
				NewValue:   150,
				Difference: 50,
				Reason:     "skill_learning",
			},
		},
	}

	charID, err := ImportCharacter(exportData, 1)
	if err != nil {
		t.Fatalf("ImportCharacter failed: %v", err)
	}

	// Verify audit log entry was imported
	var auditEntries []models.AuditLogEntry
	database.DB.Where("character_id = ?", charID).Find(&auditEntries)

	if len(auditEntries) == 0 {
		t.Error("Expected audit log entries to be imported")
	}
}

func TestImportCharacterAsJSON(t *testing.T) {
	setupImportTestEnvironment(t)

	// Export character 18 to JSON
	exportData, err := ExportCharacter(uint(18))
	if err != nil {
		t.Fatalf("Failed to export character: %v", err)
	}

	jsonData, err := json.Marshal(exportData)
	if err != nil {
		t.Fatalf("Failed to marshal to JSON: %v", err)
	}

	// Unmarshal and import
	var importData CharacterExport
	err = json.Unmarshal(jsonData, &importData)
	if err != nil {
		t.Fatalf("Failed to unmarshal JSON: %v", err)
	}

	importData.Character.ID = 0
	importData.Character.Name = "JSON Imported"

	charID, err := ImportCharacter(&importData, 1)
	if err != nil {
		t.Fatalf("ImportCharacter from JSON failed: %v", err)
	}

	if charID == 0 {
		t.Error("Expected non-zero character ID")
	}
}
