package main

import (
	"context"
	"fmt"
	"sync"
	"time"
)

// BAD: This function leaks a goroutine
func ProcessWithLeak(data string) {
	ch := make(chan string)

	// This goroutine will never exit!
	go func() {
		result := <-ch
		fmt.Println("Processed:", result)
	}()

	// If we never send on ch, the goroutine leaks
}

// GOOD: This function properly manages goroutine lifecycle
func ProcessWithContext(ctx context.Context, data string) {
	ch := make(chan string, 1) // Buffered to prevent sender blocking

	go func() {
		select {
		case result := <-ch:
			fmt.Println("Processed:", result)
		case <-ctx.Done():
			fmt.Println("Context cancelled, cleaning up")
			return
		}
	}()

	// Send data
	select {
	case ch <- data:
	case <-ctx.Done():
		return
	}
}

// GOOD: Using WaitGroup for goroutine synchronization
func ProcessWithWaitGroup(data string) {
	var wg sync.WaitGroup
	wg.Add(1)

	go func() {
		defer wg.Done()
		time.Sleep(100 * time.Millisecond)
		fmt.Println("Processed:", data)
	}()

	wg.Wait() // Wait for goroutine to complete
}

// Example of proper worker pool pattern
func WorkerPool(ctx context.Context, jobs <-chan string, numWorkers int) {
	var wg sync.WaitGroup

	for i := 0; i < numWorkers; i++ {
		wg.Add(1)
		go func(workerID int) {
			defer wg.Done()

			for {
				select {
				case job, ok := <-jobs:
					if !ok {
						// Channel closed, worker exits
						return
					}
					fmt.Printf("Worker %d processing: %s\n", workerID, job)
					time.Sleep(100 * time.Millisecond)

				case <-ctx.Done():
					// Context cancelled, worker exits
					return
				}
			}
		}(i)
	}

	wg.Wait()
}
