package channelserver

import (
	"bytes"
	"encoding/binary"
	"testing"
	"time"
)

// TestCharacterSaveDataPersistenceEdgeCases tests edge cases in character savedata persistence
func TestCharacterSaveDataPersistenceEdgeCases(t *testing.T) {
	tests := []struct {
		name      string
		charID    uint32
		charName  string
		isNew     bool
		playtime  uint32
		wantValid bool
	}{
		{
			name:      "valid_new_character",
			charID:    1,
			charName:  "TestChar",
			isNew:     true,
			playtime:  0,
			wantValid: true,
		},
		{
			name:      "existing_character_with_playtime",
			charID:    100,
			charName:  "ExistingChar",
			isNew:     false,
			playtime:  3600,
			wantValid: true,
		},
		{
			name:      "character_max_playtime",
			charID:    999,
			charName:  "MaxPlaytime",
			isNew:     false,
			playtime:  4294967295, // Max uint32
			wantValid: true,
		},
		{
			name:      "character_zero_id",
			charID:    0,
			charName:  "ZeroID",
			isNew:     true,
			playtime:  0,
			wantValid: false,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			savedata := &CharacterSaveData{
				CharID:         tt.charID,
				Name:           tt.charName,
				IsNewCharacter: tt.isNew,
				Playtime:       tt.playtime,
				Pointers:       make(map[SavePointer]int),
			}

			// Verify data integrity
			if savedata.CharID != tt.charID {
				t.Errorf("character ID mismatch: got %d, want %d", savedata.CharID, tt.charID)
			}

			if savedata.Name != tt.charName {
				t.Errorf("character name mismatch: got %s, want %s", savedata.Name, tt.charName)
			}

			if savedata.Playtime != tt.playtime {
				t.Errorf("playtime mismatch: got %d, want %d", savedata.Playtime, tt.playtime)
			}

			isValid := tt.charID > 0 && len(tt.charName) > 0
			if isValid != tt.wantValid {
				t.Errorf("validity check failed: got %v, want %v", isValid, tt.wantValid)
			}
		})
	}
}

// TestSaveDataCompressionRoundTrip tests compression/decompression edge cases
func TestSaveDataCompressionRoundTrip(t *testing.T) {
	tests := []struct {
		name        string
		dataSize    int
		dataPattern byte
		compresses  bool
	}{
		{
			name:        "empty_data",
			dataSize:    0,
			dataPattern: 0x00,
			compresses:  true,
		},
		{
			name:        "small_data",
			dataSize:    10,
			dataPattern: 0xFF,
			compresses:  false, // Small data may not compress well
		},
		{
			name:        "highly_repetitive_data",
			dataSize:    1000,
			dataPattern: 0xAA,
			compresses:  true, // Highly repetitive should compress
		},
		{
			name:        "random_data",
			dataSize:    500,
			dataPattern: 0x00, // Will be varied by position
			compresses:  false,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			// Create test data
			data := make([]byte, tt.dataSize)
			for i := 0; i < tt.dataSize; i++ {
				if tt.dataPattern == 0x00 {
					// Vary pattern for "random" data
					data[i] = byte((i * 17) % 256)
				} else {
					data[i] = tt.dataPattern
				}
			}

			// Verify data integrity after theoretical compression
			if len(data) != tt.dataSize {
				t.Errorf("data size mismatch after preparation: got %d, want %d", len(data), tt.dataSize)
			}

			// Verify data is not corrupted
			for i := 0; i < tt.dataSize; i++ {
				expectedByte := data[i]
				if data[i] != expectedByte {
					t.Errorf("data corruption at position %d", i)
					break
				}
			}
		})
	}
}

// TestSaveDataPointerHandling tests edge cases in save data pointer management
func TestSaveDataPointerHandling(t *testing.T) {
	tests := []struct {
		name            string
		pointerCount    int
		maxPointerValue int
		valid           bool
	}{
		{
			name:            "no_pointers",
			pointerCount:    0,
			maxPointerValue: 0,
			valid:           true,
		},
		{
			name:            "single_pointer",
			pointerCount:    1,
			maxPointerValue: 100,
			valid:           true,
		},
		{
			name:            "multiple_pointers",
			pointerCount:    10,
			maxPointerValue: 5000,
			valid:           true,
		},
		{
			name:            "max_pointers",
			pointerCount:    100,
			maxPointerValue: 1000000,
			valid:           true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			savedata := &CharacterSaveData{
				CharID:   1,
				Pointers: make(map[SavePointer]int),
			}

			// Add test pointers
			for i := 0; i < tt.pointerCount; i++ {
				pointer := SavePointer(i % 20) // Cycle through pointer types
				value := (i * 100) % tt.maxPointerValue
				savedata.Pointers[pointer] = value
			}

			// Verify pointer count
			if len(savedata.Pointers) != tt.pointerCount && tt.pointerCount < 20 {
				t.Errorf("pointer count mismatch: got %d, want %d", len(savedata.Pointers), tt.pointerCount)
			}

			// Verify pointer values are reasonable
			for ptr, val := range savedata.Pointers {
				if val < 0 || val > tt.maxPointerValue {
					t.Errorf("pointer %v value out of range: %d", ptr, val)
				}
			}
		})
	}
}

// TestSaveDataGenderHandling tests gender field handling
func TestSaveDataGenderHandling(t *testing.T) {
	tests := []struct {
		name   string
		gender bool
		label  string
	}{
		{
			name:   "male_character",
			gender: false,
			label:  "male",
		},
		{
			name:   "female_character",
			gender: true,
			label:  "female",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			savedata := &CharacterSaveData{
				CharID: 1,
				Gender: tt.gender,
			}

			if savedata.Gender != tt.gender {
				t.Errorf("gender mismatch: got %v, want %v", savedata.Gender, tt.gender)
			}
		})
	}
}

// TestSaveDataWeaponTypeHandling tests weapon type field handling
func TestSaveDataWeaponTypeHandling(t *testing.T) {
	tests := []struct {
		name       string
		weaponType uint8
		valid      bool
	}{
		{
			name:       "weapon_type_0",
			weaponType: 0,
			valid:      true,
		},
		{
			name:       "weapon_type_middle",
			weaponType: 5,
			valid:      true,
		},
		{
			name:       "weapon_type_max",
			weaponType: 255,
			valid:      true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			savedata := &CharacterSaveData{
				CharID:     1,
				WeaponType: tt.weaponType,
			}

			if savedata.WeaponType != tt.weaponType {
				t.Errorf("weapon type mismatch: got %d, want %d", savedata.WeaponType, tt.weaponType)
			}
		})
	}
}

// TestSaveDataRPHandling tests RP (resource points) handling
func TestSaveDataRPHandling(t *testing.T) {
	tests := []struct {
		name     string
		rpPoints uint16
		valid    bool
	}{
		{
			name:     "zero_rp",
			rpPoints: 0,
			valid:    true,
		},
		{
			name:     "moderate_rp",
			rpPoints: 1000,
			valid:    true,
		},
		{
			name:     "max_rp",
			rpPoints: 65535, // Max uint16
			valid:    true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			savedata := &CharacterSaveData{
				CharID: 1,
				RP:     tt.rpPoints,
			}

			if savedata.RP != tt.rpPoints {
				t.Errorf("RP mismatch: got %d, want %d", savedata.RP, tt.rpPoints)
			}
		})
	}
}

// TestSaveDataHousingDataHandling tests various housing/decorative data fields
func TestSaveDataHousingDataHandling(t *testing.T) {
	tests := []struct {
		name          string
		houseTier     []byte
		houseData     []byte
		bookshelfData []byte
		galleryData   []byte
		validEmpty    bool
	}{
		{
			name:          "all_empty_housing",
			houseTier:     []byte{},
			houseData:     []byte{},
			bookshelfData: []byte{},
			galleryData:   []byte{},
			validEmpty:    true,
		},
		{
			name:          "with_house_tier",
			houseTier:     []byte{0x01, 0x02, 0x03},
			houseData:     []byte{},
			bookshelfData: []byte{},
			galleryData:   []byte{},
			validEmpty:    false,
		},
		{
			name:          "all_housing_data",
			houseTier:     []byte{0xFF},
			houseData:     []byte{0xAA, 0xBB},
			bookshelfData: []byte{0xCC, 0xDD, 0xEE},
			galleryData:   []byte{0x11, 0x22, 0x33, 0x44},
			validEmpty:    false,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			savedata := &CharacterSaveData{
				CharID:        1,
				HouseTier:     tt.houseTier,
				HouseData:     tt.houseData,
				BookshelfData: tt.bookshelfData,
				GalleryData:   tt.galleryData,
			}

			if !bytes.Equal(savedata.HouseTier, tt.houseTier) {
				t.Errorf("house tier mismatch")
			}

			if !bytes.Equal(savedata.HouseData, tt.houseData) {
				t.Errorf("house data mismatch")
			}

			if !bytes.Equal(savedata.BookshelfData, tt.bookshelfData) {
				t.Errorf("bookshelf data mismatch")
			}

			if !bytes.Equal(savedata.GalleryData, tt.galleryData) {
				t.Errorf("gallery data mismatch")
			}

			isEmpty := len(tt.houseTier) == 0 && len(tt.houseData) == 0 && len(tt.bookshelfData) == 0 && len(tt.galleryData) == 0
			if isEmpty != tt.validEmpty {
				t.Errorf("empty check mismatch: got %v, want %v", isEmpty, tt.validEmpty)
			}
		})
	}
}

// TestSaveDataFieldDataHandling tests tore and garden data
func TestSaveDataFieldDataHandling(t *testing.T) {
	tests := []struct {
		name       string
		toreData   []byte
		gardenData []byte
	}{
		{
			name:       "empty_field_data",
			toreData:   []byte{},
			gardenData: []byte{},
		},
		{
			name:       "with_tore_data",
			toreData:   []byte{0x01, 0x02, 0x03, 0x04},
			gardenData: []byte{},
		},
		{
			name:       "with_garden_data",
			toreData:   []byte{},
			gardenData: []byte{0xFF, 0xFE, 0xFD},
		},
		{
			name:       "both_field_data",
			toreData:   []byte{0xAA, 0xBB},
			gardenData: []byte{0xCC, 0xDD, 0xEE},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			savedata := &CharacterSaveData{
				CharID:     1,
				ToreData:   tt.toreData,
				GardenData: tt.gardenData,
			}

			if !bytes.Equal(savedata.ToreData, tt.toreData) {
				t.Errorf("tore data mismatch")
			}

			if !bytes.Equal(savedata.GardenData, tt.gardenData) {
				t.Errorf("garden data mismatch")
			}
		})
	}
}

// TestSaveDataIntegrity tests data integrity after construction
func TestSaveDataIntegrity(t *testing.T) {
	tests := []struct {
		name   string
		runs   int
		verify func(*CharacterSaveData) bool
	}{
		{
			name: "pointers_immutable",
			runs: 10,
			verify: func(sd *CharacterSaveData) bool {
				initialPointers := len(sd.Pointers)
				sd.Pointers[SavePointer(0)] = 100
				return len(sd.Pointers) == initialPointers+1
			},
		},
		{
			name: "char_id_consistency",
			runs: 10,
			verify: func(sd *CharacterSaveData) bool {
				id := sd.CharID
				return id == sd.CharID
			},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			for run := 0; run < tt.runs; run++ {
				savedata := &CharacterSaveData{
					CharID:   uint32(run + 1),
					Name:     "TestChar",
					Pointers: make(map[SavePointer]int),
				}

				if !tt.verify(savedata) {
					t.Errorf("integrity check failed for run %d", run)
					break
				}
			}
		})
	}
}

// TestSaveDataDiffTracking tests tracking of differential updates
func TestSaveDataDiffTracking(t *testing.T) {
	tests := []struct {
		name       string
		isDiffMode bool
	}{
		{
			name:       "full_blob_mode",
			isDiffMode: false,
		},
		{
			name:       "differential_mode",
			isDiffMode: true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			// Create two savedata instances
			savedata1 := &CharacterSaveData{
				CharID: 1,
				Name:   "Char1",
				RP:     1000,
			}

			savedata2 := &CharacterSaveData{
				CharID: 1,
				Name:   "Char1",
				RP:     2000, // Different RP
			}

			// In differential mode, only changed fields would be sent
			isDifferent := savedata1.RP != savedata2.RP

			if !isDifferent && tt.isDiffMode {
				t.Error("should detect difference in differential mode")
			}

			if isDifferent {
				// Expected when there are differences
				if !tt.isDiffMode && savedata1.CharID != savedata2.CharID {
					t.Error("full blob mode should preserve all data")
				}
			}
		})
	}
}

// TestSaveDataBoundaryValues tests boundary value handling
func TestSaveDataBoundaryValues(t *testing.T) {
	tests := []struct {
		name     string
		charID   uint32
		playtime uint32
		rp       uint16
	}{
		{
			name:     "min_values",
			charID:   1, // Minimum valid ID
			playtime: 0,
			rp:       0,
		},
		{
			name:     "max_uint32_playtime",
			charID:   100,
			playtime: 4294967295,
			rp:       0,
		},
		{
			name:     "max_uint16_rp",
			charID:   100,
			playtime: 0,
			rp:       65535,
		},
		{
			name:     "all_max_values",
			charID:   4294967295,
			playtime: 4294967295,
			rp:       65535,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			savedata := &CharacterSaveData{
				CharID:   tt.charID,
				Playtime: tt.playtime,
				RP:       tt.rp,
			}

			if savedata.CharID != tt.charID {
				t.Errorf("char ID boundary check failed")
			}

			if savedata.Playtime != tt.playtime {
				t.Errorf("playtime boundary check failed")
			}

			if savedata.RP != tt.rp {
				t.Errorf("RP boundary check failed")
			}
		})
	}
}

// TestSaveDataSerialization tests savedata can be serialized to binary format
func TestSaveDataSerialization(t *testing.T) {
	tests := []struct {
		name     string
		charID   uint32
		playtime uint32
	}{
		{
			name:     "simple_serialization",
			charID:   1,
			playtime: 100,
		},
		{
			name:     "large_playtime",
			charID:   999,
			playtime: 1000000,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			savedata := &CharacterSaveData{
				CharID:   tt.charID,
				Playtime: tt.playtime,
			}

			// Simulate binary serialization
			buf := new(bytes.Buffer)
			_ = binary.Write(buf, binary.LittleEndian, savedata.CharID)
			_ = binary.Write(buf, binary.LittleEndian, savedata.Playtime)

			// Should have 8 bytes (4 + 4)
			if buf.Len() != 8 {
				t.Errorf("serialized size mismatch: got %d, want 8", buf.Len())
			}

			// Deserialize and verify
			data := buf.Bytes()
			var charID uint32
			var playtime uint32
			_ = binary.Read(bytes.NewReader(data), binary.LittleEndian, &charID)
			_ = binary.Read(bytes.NewReader(data[4:]), binary.LittleEndian, &playtime)

			if charID != tt.charID || playtime != tt.playtime {
				t.Error("serialization round-trip failed")
			}
		})
	}
}

// TestSaveDataTimestampHandling tests timestamp field handling for data freshness
func TestSaveDataTimestampHandling(t *testing.T) {
	tests := []struct {
		name        string
		ageSeconds  int
		expectFresh bool
	}{
		{
			name:        "just_saved",
			ageSeconds:  0,
			expectFresh: true,
		},
		{
			name:        "recent_save",
			ageSeconds:  60,
			expectFresh: true,
		},
		{
			name:        "old_save",
			ageSeconds:  86400, // 1 day old
			expectFresh: false,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			now := time.Now()
			lastSave := now.Add(time.Duration(-tt.ageSeconds) * time.Second)

			// Simulate freshness check
			age := now.Sub(lastSave)
			isFresh := age < 3600*time.Second // 1 hour

			if isFresh != tt.expectFresh {
				t.Errorf("freshness check failed: got %v, want %v", isFresh, tt.expectFresh)
			}
		})
	}
}

// TestDataCorruptionRecovery tests recovery from corrupted savedata
func TestDataCorruptionRecovery(t *testing.T) {
	tests := []struct {
		name           string
		originalData   []byte
		corruptedData  []byte
		canRecover     bool
		recoveryMethod string
	}{
		{
			name:           "minor_bit_flip",
			originalData:   []byte{0xFF, 0xFF, 0xFF, 0xFF},
			corruptedData:  []byte{0xFF, 0xFE, 0xFF, 0xFF}, // One bit flipped
			canRecover:     true,
			recoveryMethod: "checksum_validation",
		},
		{
			name:           "single_byte_corruption",
			originalData:   []byte{0x00, 0x01, 0x02, 0x03, 0x04},
			corruptedData:  []byte{0x00, 0xFF, 0x02, 0x03, 0x04}, // Middle byte corrupted
			canRecover:     true,
			recoveryMethod: "crc32_check",
		},
		{
			name:           "data_truncation",
			originalData:   []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05},
			corruptedData:  []byte{0x00, 0x01}, // Truncated
			canRecover:     true,
			recoveryMethod: "length_validation",
		},
		{
			name:           "complete_garbage",
			originalData:   []byte{0x00, 0x01, 0x02},
			corruptedData:  []byte{}, // Empty/no data
			canRecover:     false,
			recoveryMethod: "none",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			// Simulate corruption detection
			isCorrupted := !bytes.Equal(tt.originalData, tt.corruptedData)

			if isCorrupted && tt.canRecover {
				// Try recovery validation based on method
				canRecover := false
				switch tt.recoveryMethod {
				case "checksum_validation":
					// Simple checksum check
					canRecover = len(tt.corruptedData) == len(tt.originalData)
				case "crc32_check":
					// Length should match
					canRecover = len(tt.corruptedData) == len(tt.originalData)
				case "length_validation":
					// Can recover if we have partial data
					canRecover = len(tt.corruptedData) > 0
				}

				if !canRecover && tt.canRecover {
					t.Errorf("failed to recover from corruption using %s", tt.recoveryMethod)
				}
			}
		})
	}
}

// TestChecksumValidation tests savedata checksum validation
func TestChecksumValidation(t *testing.T) {
	tests := []struct {
		name          string
		data          []byte
		checksumValid bool
	}{
		{
			name:          "valid_checksum",
			data:          []byte{0x01, 0x02, 0x03, 0x04},
			checksumValid: true,
		},
		{
			name:          "corrupted_data_fails_checksum",
			data:          []byte{0xFF, 0xFF, 0xFF, 0xFF},
			checksumValid: true, // Checksum can still be valid, but content is suspicious
		},
		{
			name:          "empty_data_valid_checksum",
			data:          []byte{},
			checksumValid: true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			// Calculate simple checksum
			var checksum byte
			for _, b := range tt.data {
				checksum ^= b
			}

			// Verify checksum can be calculated
			_ = (len(tt.data) > 0 && checksum == 0xFF && len(tt.data) == 4 && tt.data[0] == 0xFF)
			// Expected for all 0xFF data

			// If original passes checksum, verify it's consistent
			checksum2 := byte(0)
			for _, b := range tt.data {
				checksum2 ^= b
			}

			if checksum != checksum2 {
				t.Error("checksum calculation not consistent")
			}
		})
	}
}

// TestSaveDataBackupRestoration tests backup and restoration functionality
func TestSaveDataBackupRestoration(t *testing.T) {
	tests := []struct {
		name             string
		originalCharID   uint32
		originalPlaytime uint32
		hasBackup        bool
		canRestore       bool
	}{
		{
			name:             "backup_with_restore",
			originalCharID:   1,
			originalPlaytime: 1000,
			hasBackup:        true,
			canRestore:       true,
		},
		{
			name:             "no_backup_available",
			originalCharID:   2,
			originalPlaytime: 2000,
			hasBackup:        false,
			canRestore:       false,
		},
		{
			name:             "backup_corrupt_fallback",
			originalCharID:   3,
			originalPlaytime: 3000,
			hasBackup:        true,
			canRestore:       true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			// Create original data
			original := &CharacterSaveData{
				CharID:   tt.originalCharID,
				Playtime: tt.originalPlaytime,
			}

			// Create backup
			var backup *CharacterSaveData
			if tt.hasBackup {
				backup = &CharacterSaveData{
					CharID:   original.CharID,
					Playtime: original.Playtime,
				}
			}

			// Simulate data corruption
			original.Playtime = 9999

			// Try restoration
			if tt.canRestore && backup != nil {
				// Restore from backup
				original.Playtime = backup.Playtime
			}

			// Verify restoration worked
			if tt.canRestore && backup != nil {
				if original.Playtime != tt.originalPlaytime {
					t.Errorf("restoration failed: got %d, want %d", original.Playtime, tt.originalPlaytime)
				}
			}
		})
	}
}

// TestSaveDataVersionMigration tests savedata version migration and compatibility
func TestSaveDataVersionMigration(t *testing.T) {
	tests := []struct {
		name          string
		sourceVersion int
		targetVersion int
		canMigrate    bool
		dataLoss      bool
	}{
		{
			name:          "same_version",
			sourceVersion: 1,
			targetVersion: 1,
			canMigrate:    true,
			dataLoss:      false,
		},
		{
			name:          "forward_compatible",
			sourceVersion: 1,
			targetVersion: 2,
			canMigrate:    true,
			dataLoss:      false,
		},
		{
			name:          "backward_compatible",
			sourceVersion: 2,
			targetVersion: 1,
			canMigrate:    true,
			dataLoss:      true, // Newer fields might be lost
		},
		{
			name:          "incompatible_versions",
			sourceVersion: 1,
			targetVersion: 10,
			canMigrate:    false,
			dataLoss:      true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			// Determine migration compatibility
			canMigrate := false
			dataLoss := false

			versionDiff := tt.targetVersion - tt.sourceVersion
			if versionDiff == 0 {
				canMigrate = true
			} else if versionDiff == 1 {
				canMigrate = true // Forward migration by one version
				dataLoss = false
			} else if versionDiff < 0 {
				canMigrate = true // Backward migration
				dataLoss = true
			} else if versionDiff > 2 {
				canMigrate = false // Too many versions apart
				dataLoss = true
			}

			if canMigrate != tt.canMigrate {
				t.Errorf("migration capability mismatch: got %v, want %v", canMigrate, tt.canMigrate)
			}

			if dataLoss != tt.dataLoss {
				t.Errorf("data loss expectation mismatch: got %v, want %v", dataLoss, tt.dataLoss)
			}
		})
	}
}

// TestSaveDataRollback tests rollback to previous savedata state
func TestSaveDataRollback(t *testing.T) {
	tests := []struct {
		name          string
		snapshots     int
		canRollback   bool
		rollbackSteps int
	}{
		{
			name:          "single_snapshot",
			snapshots:     1,
			canRollback:   false,
			rollbackSteps: 0,
		},
		{
			name:          "multiple_snapshots",
			snapshots:     5,
			canRollback:   true,
			rollbackSteps: 2,
		},
		{
			name:          "many_snapshots",
			snapshots:     100,
			canRollback:   true,
			rollbackSteps: 50,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			// Create snapshot history
			snapshots := make([]*CharacterSaveData, tt.snapshots)
			for i := 0; i < tt.snapshots; i++ {
				snapshots[i] = &CharacterSaveData{
					CharID:   1,
					Playtime: uint32(i * 100),
				}
			}

			// Can only rollback if we have more than one snapshot
			canRollback := len(snapshots) > 1

			if canRollback != tt.canRollback {
				t.Errorf("rollback capability mismatch: got %v, want %v", canRollback, tt.canRollback)
			}

			// Test rollback steps
			if canRollback && tt.rollbackSteps > 0 {
				if tt.rollbackSteps >= len(snapshots) {
					t.Error("rollback steps exceed available snapshots")
				}

				// Simulate rollback
				currentIdx := len(snapshots) - 1
				targetIdx := currentIdx - tt.rollbackSteps
				if targetIdx >= 0 {
					rolledBackData := snapshots[targetIdx]
					expectedPlaytime := uint32(targetIdx * 100)
					if rolledBackData.Playtime != expectedPlaytime {
						t.Errorf("rollback verification failed: got %d, want %d", rolledBackData.Playtime, expectedPlaytime)
					}
				}
			}
		})
	}
}

// TestSaveDataValidationOnLoad tests validation when loading savedata
func TestSaveDataValidationOnLoad(t *testing.T) {
	tests := []struct {
		name       string
		charID     uint32
		charName   string
		isNew      bool
		shouldPass bool
	}{
		{
			name:       "valid_load",
			charID:     1,
			charName:   "TestChar",
			isNew:      false,
			shouldPass: true,
		},
		{
			name:       "invalid_zero_id",
			charID:     0,
			charName:   "TestChar",
			isNew:      false,
			shouldPass: false,
		},
		{
			name:       "empty_name",
			charID:     1,
			charName:   "",
			isNew:      true,
			shouldPass: false,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			// Validate on load
			isValid := tt.charID > 0 && len(tt.charName) > 0

			if isValid != tt.shouldPass {
				t.Errorf("validation check failed: got %v, want %v", isValid, tt.shouldPass)
			}
		})
	}
}

// TestSaveDataConcurrentAccess tests concurrent access to savedata structures
func TestSaveDataConcurrentAccess(t *testing.T) {
	tests := []struct {
		name             string
		concurrentReads  int
		concurrentWrites int
	}{
		{
			name:             "multiple_readers",
			concurrentReads:  5,
			concurrentWrites: 0,
		},
		{
			name:             "multiple_writers",
			concurrentReads:  0,
			concurrentWrites: 3,
		},
		{
			name:             "mixed_access",
			concurrentReads:  3,
			concurrentWrites: 2,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			// This is a structural test - actual concurrent access would need mutexes
			savedata := &CharacterSaveData{
				CharID:   1,
				Playtime: 0,
			}

			// Simulate concurrent operations
			totalOps := tt.concurrentReads + tt.concurrentWrites
			if totalOps == 0 {
				t.Skip("no concurrent operations to test")
			}

			// Verify savedata structure is intact
			if savedata.CharID != 1 {
				t.Error("savedata corrupted by concurrent access test")
			}
		})
	}
}
