/*
Package utils provides common utility functions used across all modules.
This file contains safe slice operations to prevent index out of bounds errors.
*/
package utils

// RemoveAtIndex safely removes an element at the specified index from a slice.
// It returns a new slice with the element removed.
//
// This function handles edge cases safely:
//   - Returns nil if the input slice is nil
//   - Returns an empty slice if the input slice is empty
//   - Returns the original slice unchanged if the index is out of bounds (negative or >= length)
//
// The function does not panic on invalid input.
//
// Example:
//
//	slice := []string{"a", "b", "c", "d"}
//	result := RemoveAtIndex(slice, 1) // Returns ["a", "c", "d"]
//
// Validates: Requirement 6.3 - Safe slice removal to avoid index out of bounds
func RemoveAtIndex[T any](slice []T, index int) []T {
	// Handle nil slice
	if slice == nil {
		return nil
	}

	// Handle empty slice
	if len(slice) == 0 {
		return []T{}
	}

	// Handle invalid index (negative or out of bounds)
	if index < 0 || index >= len(slice) {
		// Return a copy of the original slice to maintain immutability
		result := make([]T, len(slice))
		copy(result, slice)
		return result
	}

	// Create a new slice with capacity for len-1 elements
	result := make([]T, 0, len(slice)-1)

	// Copy elements before the index
	result = append(result, slice[:index]...)

	// Copy elements after the index
	result = append(result, slice[index+1:]...)

	return result
}

// RemoveAtIndexInPlace removes an element at the specified index from a slice in place.
// It modifies the original slice and returns the modified slice.
//
// This function handles edge cases safely:
//   - Returns nil if the input slice is nil
//   - Returns an empty slice if the input slice is empty
//   - Returns the original slice unchanged if the index is out of bounds (negative or >= length)
//
// The function does not panic on invalid input.
//
// Note: This function modifies the original slice. Use RemoveAtIndex if you need
// to preserve the original slice.
//
// Example:
//
//	slice := []string{"a", "b", "c", "d"}
//	slice = RemoveAtIndexInPlace(slice, 1) // slice is now ["a", "c", "d"]
//
// Validates: Requirement 6.3 - Safe slice removal to avoid index out of bounds
func RemoveAtIndexInPlace[T any](slice []T, index int) []T {
	// Handle nil slice
	if slice == nil {
		return nil
	}

	// Handle empty slice
	if len(slice) == 0 {
		return slice
	}

	// Handle invalid index (negative or out of bounds)
	if index < 0 || index >= len(slice) {
		return slice
	}

	// Shift elements to the left starting from the index
	copy(slice[index:], slice[index+1:])

	// Return the slice with reduced length
	return slice[:len(slice)-1]
}

// SafeGet safely retrieves an element at the specified index from a slice.
// It returns the element and a boolean indicating whether the retrieval was successful.
//
// This function handles edge cases safely:
//   - Returns zero value and false if the slice is nil
//   - Returns zero value and false if the slice is empty
//   - Returns zero value and false if the index is out of bounds
//
// The function does not panic on invalid input.
//
// Example:
//
//	slice := []string{"a", "b", "c"}
//	val, ok := SafeGet(slice, 1) // Returns "b", true
//	val, ok := SafeGet(slice, 5) // Returns "", false
//
// Validates: Requirement 6.3 - Safe slice operations to avoid index out of bounds
func SafeGet[T any](slice []T, index int) (T, bool) {
	var zero T

	// Handle nil slice
	if slice == nil {
		return zero, false
	}

	// Handle empty slice or invalid index
	if len(slice) == 0 || index < 0 || index >= len(slice) {
		return zero, false
	}

	return slice[index], true
}
