/*
Package utils provides common utility functions used across all modules.
This file contains property-based tests for safe slice operations.

Feature: autosso-refactoring, Property 12: 切片安全删除
*对于任意* 切片和要删除的索引，删除操作后切片长度应减少 1，且不应发生索引越界。

**Validates: Requirements 6.3**
*/
package utils

import (
	"reflect"
	"testing"

	"pgregory.net/rapid"
)

// TestProperty12_SliceSafeDeletion_LengthReduction tests that for any slice and valid index,
// the result slice length is reduced by 1.
//
// Feature: autosso-refactoring, Property 12: 切片安全删除
// **Validates: Requirements 6.3**
func TestProperty12_SliceSafeDeletion_LengthReduction(t *testing.T) {
	rapid.Check(t, func(rt *rapid.T) {
		// Generate a non-empty slice of strings
		sliceLen := rapid.IntRange(1, 100).Draw(rt, "sliceLen")
		slice := make([]string, sliceLen)
		for i := 0; i < sliceLen; i++ {
			slice[i] = rapid.String().Draw(rt, "element")
		}

		// Generate a valid index within bounds
		validIndex := rapid.IntRange(0, sliceLen-1).Draw(rt, "validIndex")

		// Perform the removal
		result := RemoveAtIndex(slice, validIndex)

		// Property: Result length should be original length - 1
		expectedLen := sliceLen - 1
		if len(result) != expectedLen {
			rt.Fatalf("Length reduction failed:\n"+
				"Original slice length: %d\n"+
				"Index to remove: %d\n"+
				"Expected result length: %d\n"+
				"Actual result length: %d",
				sliceLen, validIndex, expectedLen, len(result))
		}
	})
}

// TestProperty12_SliceSafeDeletion_NoPanicOnInvalidIndex tests that for any slice and
// invalid index (negative or >= length), no panic occurs.
//
// Feature: autosso-refactoring, Property 12: 切片安全删除
// **Validates: Requirements 6.3**
func TestProperty12_SliceSafeDeletion_NoPanicOnInvalidIndex(t *testing.T) {
	rapid.Check(t, func(rt *rapid.T) {
		// Generate a slice of arbitrary length (including empty)
		sliceLen := rapid.IntRange(0, 100).Draw(rt, "sliceLen")
		slice := make([]string, sliceLen)
		for i := 0; i < sliceLen; i++ {
			slice[i] = rapid.String().Draw(rt, "element")
		}

		// Generate an invalid index (negative or >= length)
		invalidIndex := rapid.OneOf(
			// Negative indices
			rapid.IntRange(-1000, -1),
			// Indices >= length (for non-empty slices, this is >= sliceLen; for empty, any non-negative)
			rapid.Custom(func(t *rapid.T) int {
				if sliceLen == 0 {
					return rapid.IntRange(0, 1000).Draw(t, "outOfBounds")
				}
				return rapid.IntRange(sliceLen, sliceLen+1000).Draw(t, "outOfBounds")
			}),
		).Draw(rt, "invalidIndex")

		// This should NOT panic - wrap in a deferred recover to catch any panic
		defer func() {
			if r := recover(); r != nil {
				rt.Fatalf("RemoveAtIndex panicked with invalid index:\n"+
					"Slice length: %d\n"+
					"Invalid index: %d\n"+
					"Panic: %v",
					sliceLen, invalidIndex, r)
			}
		}()

		// Perform the removal - should not panic
		result := RemoveAtIndex(slice, invalidIndex)

		// Property: For invalid index, result should have same length as original
		if len(result) != sliceLen {
			rt.Fatalf("Invalid index handling failed:\n"+
				"Original slice length: %d\n"+
				"Invalid index: %d\n"+
				"Expected result length: %d (unchanged)\n"+
				"Actual result length: %d",
				sliceLen, invalidIndex, sliceLen, len(result))
		}
	})
}

// TestProperty12_SliceSafeDeletion_Immutability tests that the original slice
// is not modified after removal (immutability).
//
// Feature: autosso-refactoring, Property 12: 切片安全删除
// **Validates: Requirements 6.3**
func TestProperty12_SliceSafeDeletion_Immutability(t *testing.T) {
	rapid.Check(t, func(rt *rapid.T) {
		// Generate a non-empty slice of strings
		sliceLen := rapid.IntRange(1, 100).Draw(rt, "sliceLen")
		slice := make([]string, sliceLen)
		for i := 0; i < sliceLen; i++ {
			slice[i] = rapid.String().Draw(rt, "element")
		}

		// Make a deep copy of the original slice for comparison
		originalCopy := make([]string, len(slice))
		copy(originalCopy, slice)

		// Generate a valid index
		validIndex := rapid.IntRange(0, sliceLen-1).Draw(rt, "validIndex")

		// Perform the removal
		_ = RemoveAtIndex(slice, validIndex)

		// Property: Original slice should remain unchanged
		if !reflect.DeepEqual(slice, originalCopy) {
			rt.Fatalf("Immutability violated:\n"+
				"Original slice was modified after RemoveAtIndex\n"+
				"Index removed: %d\n"+
				"Expected original: %v\n"+
				"Actual original: %v",
				validIndex, originalCopy, slice)
		}
	})
}

// TestProperty12_SliceSafeDeletion_ElementsPreserved tests that all elements
// except the removed one are preserved in the result.
//
// Feature: autosso-refactoring, Property 12: 切片安全删除
// **Validates: Requirements 6.3**
func TestProperty12_SliceSafeDeletion_ElementsPreserved(t *testing.T) {
	rapid.Check(t, func(rt *rapid.T) {
		// Generate a non-empty slice of strings
		sliceLen := rapid.IntRange(1, 100).Draw(rt, "sliceLen")
		slice := make([]string, sliceLen)
		for i := 0; i < sliceLen; i++ {
			slice[i] = rapid.String().Draw(rt, "element")
		}

		// Generate a valid index
		validIndex := rapid.IntRange(0, sliceLen-1).Draw(rt, "validIndex")

		// Perform the removal
		result := RemoveAtIndex(slice, validIndex)

		// Property: All elements before the removed index should be preserved
		for i := 0; i < validIndex; i++ {
			if result[i] != slice[i] {
				rt.Fatalf("Element before removed index not preserved:\n"+
					"Index: %d\n"+
					"Removed index: %d\n"+
					"Expected: %q\n"+
					"Got: %q",
					i, validIndex, slice[i], result[i])
			}
		}

		// Property: All elements after the removed index should be shifted left by 1
		for i := validIndex; i < len(result); i++ {
			if result[i] != slice[i+1] {
				rt.Fatalf("Element after removed index not correctly shifted:\n"+
					"Result index: %d\n"+
					"Original index: %d\n"+
					"Removed index: %d\n"+
					"Expected: %q\n"+
					"Got: %q",
					i, i+1, validIndex, slice[i+1], result[i])
			}
		}
	})
}

// TestProperty12_SliceSafeDeletion_IntSlice tests the property with integer slices
// to verify generic type support.
//
// Feature: autosso-refactoring, Property 12: 切片安全删除
// **Validates: Requirements 6.3**
func TestProperty12_SliceSafeDeletion_IntSlice(t *testing.T) {
	rapid.Check(t, func(rt *rapid.T) {
		// Generate a non-empty slice of integers
		sliceLen := rapid.IntRange(1, 100).Draw(rt, "sliceLen")
		slice := make([]int, sliceLen)
		for i := 0; i < sliceLen; i++ {
			slice[i] = rapid.Int().Draw(rt, "element")
		}

		// Generate a valid index
		validIndex := rapid.IntRange(0, sliceLen-1).Draw(rt, "validIndex")

		// Perform the removal
		result := RemoveAtIndex(slice, validIndex)

		// Property: Result length should be original length - 1
		if len(result) != sliceLen-1 {
			rt.Fatalf("Length reduction failed for int slice:\n"+
				"Original length: %d\n"+
				"Expected result length: %d\n"+
				"Actual result length: %d",
				sliceLen, sliceLen-1, len(result))
		}

		// Property: Elements should be preserved correctly
		for i := 0; i < validIndex; i++ {
			if result[i] != slice[i] {
				rt.Fatalf("Element before removed index not preserved in int slice:\n"+
					"Index: %d, Expected: %d, Got: %d",
					i, slice[i], result[i])
			}
		}
		for i := validIndex; i < len(result); i++ {
			if result[i] != slice[i+1] {
				rt.Fatalf("Element after removed index not correctly shifted in int slice:\n"+
					"Result index: %d, Expected: %d, Got: %d",
					i, slice[i+1], result[i])
			}
		}
	})
}

// TestProperty12_SliceSafeDeletion_NilSlice tests that nil slices are handled safely.
//
// Feature: autosso-refactoring, Property 12: 切片安全删除
// **Validates: Requirements 6.3**
func TestProperty12_SliceSafeDeletion_NilSlice(t *testing.T) {
	rapid.Check(t, func(rt *rapid.T) {
		// Generate any index (valid or invalid)
		index := rapid.IntRange(-100, 100).Draw(rt, "index")

		// This should NOT panic
		defer func() {
			if r := recover(); r != nil {
				rt.Fatalf("RemoveAtIndex panicked with nil slice:\n"+
					"Index: %d\n"+
					"Panic: %v",
					index, r)
			}
		}()

		var nilSlice []string = nil
		result := RemoveAtIndex(nilSlice, index)

		// Property: Result should be nil for nil input
		if result != nil {
			rt.Fatalf("Nil slice handling failed:\n"+
				"Expected: nil\n"+
				"Got: %v",
				result)
		}
	})
}

// TestProperty12_SliceSafeDeletion_EmptySlice tests that empty slices are handled safely.
//
// Feature: autosso-refactoring, Property 12: 切片安全删除
// **Validates: Requirements 6.3**
func TestProperty12_SliceSafeDeletion_EmptySlice(t *testing.T) {
	rapid.Check(t, func(rt *rapid.T) {
		// Generate any index (all indices are invalid for empty slice)
		index := rapid.IntRange(-100, 100).Draw(rt, "index")

		// This should NOT panic
		defer func() {
			if r := recover(); r != nil {
				rt.Fatalf("RemoveAtIndex panicked with empty slice:\n"+
					"Index: %d\n"+
					"Panic: %v",
					index, r)
			}
		}()

		emptySlice := []string{}
		result := RemoveAtIndex(emptySlice, index)

		// Property: Result should be empty for empty input
		if len(result) != 0 {
			rt.Fatalf("Empty slice handling failed:\n"+
				"Expected length: 0\n"+
				"Got length: %d",
				len(result))
		}
	})
}

// TestProperty12_SliceSafeDeletion_StructSlice tests the property with struct slices
// to verify complex type support.
//
// Feature: autosso-refactoring, Property 12: 切片安全删除
// **Validates: Requirements 6.3**
func TestProperty12_SliceSafeDeletion_StructSlice(t *testing.T) {
	type TestStruct struct {
		ID   int
		Name string
	}

	rapid.Check(t, func(rt *rapid.T) {
		// Generate a non-empty slice of structs
		sliceLen := rapid.IntRange(1, 50).Draw(rt, "sliceLen")
		slice := make([]TestStruct, sliceLen)
		for i := 0; i < sliceLen; i++ {
			slice[i] = TestStruct{
				ID:   rapid.Int().Draw(rt, "id"),
				Name: rapid.String().Draw(rt, "name"),
			}
		}

		// Generate a valid index
		validIndex := rapid.IntRange(0, sliceLen-1).Draw(rt, "validIndex")

		// Perform the removal
		result := RemoveAtIndex(slice, validIndex)

		// Property: Result length should be original length - 1
		if len(result) != sliceLen-1 {
			rt.Fatalf("Length reduction failed for struct slice:\n"+
				"Original length: %d\n"+
				"Expected result length: %d\n"+
				"Actual result length: %d",
				sliceLen, sliceLen-1, len(result))
		}

		// Property: Elements should be preserved correctly
		for i := 0; i < validIndex; i++ {
			if result[i] != slice[i] {
				rt.Fatalf("Struct element before removed index not preserved:\n"+
					"Index: %d, Expected: %+v, Got: %+v",
					i, slice[i], result[i])
			}
		}
		for i := validIndex; i < len(result); i++ {
			if result[i] != slice[i+1] {
				rt.Fatalf("Struct element after removed index not correctly shifted:\n"+
					"Result index: %d, Expected: %+v, Got: %+v",
					i, slice[i+1], result[i])
			}
		}
	})
}

// TestProperty12_RemoveAtIndexInPlace_LengthReduction tests the in-place variant
// for length reduction property.
//
// Feature: autosso-refactoring, Property 12: 切片安全删除
// **Validates: Requirements 6.3**
func TestProperty12_RemoveAtIndexInPlace_LengthReduction(t *testing.T) {
	rapid.Check(t, func(rt *rapid.T) {
		// Generate a non-empty slice of strings
		sliceLen := rapid.IntRange(1, 100).Draw(rt, "sliceLen")
		slice := make([]string, sliceLen)
		for i := 0; i < sliceLen; i++ {
			slice[i] = rapid.String().Draw(rt, "element")
		}

		// Generate a valid index
		validIndex := rapid.IntRange(0, sliceLen-1).Draw(rt, "validIndex")

		// Perform the in-place removal
		result := RemoveAtIndexInPlace(slice, validIndex)

		// Property: Result length should be original length - 1
		expectedLen := sliceLen - 1
		if len(result) != expectedLen {
			rt.Fatalf("In-place length reduction failed:\n"+
				"Original slice length: %d\n"+
				"Index to remove: %d\n"+
				"Expected result length: %d\n"+
				"Actual result length: %d",
				sliceLen, validIndex, expectedLen, len(result))
		}
	})
}

// TestProperty12_RemoveAtIndexInPlace_NoPanicOnInvalidIndex tests the in-place variant
// for no panic on invalid index.
//
// Feature: autosso-refactoring, Property 12: 切片安全删除
// **Validates: Requirements 6.3**
func TestProperty12_RemoveAtIndexInPlace_NoPanicOnInvalidIndex(t *testing.T) {
	rapid.Check(t, func(rt *rapid.T) {
		// Generate a slice of arbitrary length
		sliceLen := rapid.IntRange(0, 100).Draw(rt, "sliceLen")
		slice := make([]string, sliceLen)
		for i := 0; i < sliceLen; i++ {
			slice[i] = rapid.String().Draw(rt, "element")
		}

		// Generate an invalid index
		invalidIndex := rapid.OneOf(
			rapid.IntRange(-1000, -1),
			rapid.Custom(func(t *rapid.T) int {
				if sliceLen == 0 {
					return rapid.IntRange(0, 1000).Draw(t, "outOfBounds")
				}
				return rapid.IntRange(sliceLen, sliceLen+1000).Draw(t, "outOfBounds")
			}),
		).Draw(rt, "invalidIndex")

		// This should NOT panic
		defer func() {
			if r := recover(); r != nil {
				rt.Fatalf("RemoveAtIndexInPlace panicked with invalid index:\n"+
					"Slice length: %d\n"+
					"Invalid index: %d\n"+
					"Panic: %v",
					sliceLen, invalidIndex, r)
			}
		}()

		// Perform the in-place removal - should not panic
		result := RemoveAtIndexInPlace(slice, invalidIndex)

		// Property: For invalid index, result should have same length as original
		if len(result) != sliceLen {
			rt.Fatalf("In-place invalid index handling failed:\n"+
				"Original slice length: %d\n"+
				"Invalid index: %d\n"+
				"Expected result length: %d (unchanged)\n"+
				"Actual result length: %d",
				sliceLen, invalidIndex, sliceLen, len(result))
		}
	})
}

// TestProperty12_SafeGet_NoPanicOnAnyIndex tests that SafeGet never panics
// regardless of the index provided.
//
// Feature: autosso-refactoring, Property 12: 切片安全删除
// **Validates: Requirements 6.3**
func TestProperty12_SafeGet_NoPanicOnAnyIndex(t *testing.T) {
	rapid.Check(t, func(rt *rapid.T) {
		// Generate a slice of arbitrary length (including empty)
		sliceLen := rapid.IntRange(0, 100).Draw(rt, "sliceLen")
		slice := make([]string, sliceLen)
		for i := 0; i < sliceLen; i++ {
			slice[i] = rapid.String().Draw(rt, "element")
		}

		// Generate any index (valid or invalid)
		index := rapid.IntRange(-1000, 1000).Draw(rt, "index")

		// This should NOT panic
		defer func() {
			if r := recover(); r != nil {
				rt.Fatalf("SafeGet panicked:\n"+
					"Slice length: %d\n"+
					"Index: %d\n"+
					"Panic: %v",
					sliceLen, index, r)
			}
		}()

		// Perform the safe get
		val, ok := SafeGet(slice, index)

		// Property: ok should be true only for valid indices
		isValidIndex := index >= 0 && index < sliceLen
		if ok != isValidIndex {
			rt.Fatalf("SafeGet ok value incorrect:\n"+
				"Slice length: %d\n"+
				"Index: %d\n"+
				"Expected ok: %v\n"+
				"Actual ok: %v",
				sliceLen, index, isValidIndex, ok)
		}

		// Property: If ok is true, value should match the slice element
		if ok && val != slice[index] {
			rt.Fatalf("SafeGet returned wrong value:\n"+
				"Index: %d\n"+
				"Expected: %q\n"+
				"Got: %q",
				index, slice[index], val)
		}

		// Property: If ok is false, value should be zero value
		if !ok && val != "" {
			rt.Fatalf("SafeGet should return zero value when ok is false:\n"+
				"Index: %d\n"+
				"Expected: empty string\n"+
				"Got: %q",
				index, val)
		}
	})
}
