package numeric

import (
	"reflect"

	"github.com/spf13/cast"

	"github.com/go-sprout/sprout"
)

// operateNumeric applies a numericOperation to a slice of any type, converting
// to and from float64. The result is converted back to the type of the first
// element in the slice.
//
// Parameters:
//
//	values []any - Slice of numeric values.
//	op numericOperation - Function to apply.
//	initial float64 - Starting value for the operation.
//
// Returns:
//
//	any - Result of the operation, converted to the type of the first slice element.
func operateNumeric(values []any, op numericOperation, initial any) (any, error) {
	if len(values) == 0 {
		return initial, nil
	}

	result, err := cast.ToFloat64E(values[0])
	if err != nil {
		return 0.0, sprout.NewErrConvertFailed("float64", values[0], err)
	}
	for _, value := range values[1:] {
		floatValue, err := cast.ToFloat64E(value)
		if err != nil {
			return 0.0, sprout.NewErrConvertFailed("float64", value, err)
		}
		result = op(result, floatValue)
	}

	// Direct type assertion for common types to avoid reflection overhead
	initialType := reflect.TypeOf(values[0])
	switch initialType.Kind() {
	case reflect.Int:
		return int(result), nil
	case reflect.Float64:
		return result, nil
	default:
		return reflect.ValueOf(result).Convert(initialType).Interface(), nil
	}
}
