package core

import "sync"

// MapConcurrent applies fn to each element of xs using a pool of worker goroutines.
// The number of concurrent workers is capped by the workers parameter.
// Results preserve the original index order. If workers <= 0, it defaults to 1.
func MapConcurrent[T any, U any](xs []T, fn func(T) U, workers int) []U {
	if workers <= 0 {
		workers = 1
	}
	n := len(xs)
	if n == 0 {
		return []U{}
	}

	results := make([]U, n)
	var wg sync.WaitGroup
	ch := make(chan int, n)

	// Feed indices into the channel.
	for i := range xs {
		ch <- i
	}
	close(ch)

	// Spawn workers.
	if workers > n {
		workers = n
	}
	wg.Add(workers)
	for w := 0; w < workers; w++ {
		go func() {
			defer wg.Done()
			for i := range ch {
				results[i] = fn(xs[i])
			}
		}()
	}

	wg.Wait()
	return results
}
