package main

import (
	"context"
	"errors"
	"fmt"
	"time"

	"github.com/alitto/pond/v2"
)

func main() {
	// Create a worker pool with max 5 workers
	pool := pond.NewPool(5)

	// Submit tasks
	for i := 0; i < 10; i++ {
		i := i
		pool.Submit(func() {
			fmt.Printf("Task %d running on pool\n", i)
			time.Sleep(50 * time.Millisecond)
		})
	}

	// Wait for all tasks to complete and stop pool
	pool.StopAndWait()

	// Pool with result type using generics
	resultPool := pond.NewResultPool[int](5)

	// Submit tasks that return values
	task1 := resultPool.Submit(func() int {
		time.Sleep(50 * time.Millisecond)
		return 42
	})

	task2 := resultPool.Submit(func() int {
		time.Sleep(30 * time.Millisecond)
		return 100
	})

	// Get results (blocks until complete)
	result1, _ := task1.Wait()
	result2, _ := task2.Wait()
	fmt.Printf("Results: %d, %d\n", result1, result2)
	resultPool.StopAndWait()

	// Pool with context for cancellation
	ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond)
	defer cancel()

	ctxPool := pond.NewPool(3, pond.WithContext(ctx))

	for i := 0; i < 5; i++ {
		i := i
		ctxPool.Submit(func() {
			select {
			case <-ctx.Done():
				fmt.Printf("Task %d cancelled\n", i)
				return
			case <-time.After(100 * time.Millisecond):
				fmt.Printf("Task %d completed\n", i)
			}
		})
	}
	ctxPool.StopAndWait()

	// Task groups for coordinating related tasks
	pool2 := pond.NewPool(5)
	group := pool2.NewGroup()

	for i := 0; i < 5; i++ {
		i := i
		group.Submit(func() {
			fmt.Printf("Group task %d\n", i)
			time.Sleep(20 * time.Millisecond)
		})
	}

	// Wait only for this group's tasks
	group.Wait()
	fmt.Println("Group completed")
	pool2.StopAndWait()

	// Result pool with errors
	errPool := pond.NewResultPool[string](3)

	successTask := errPool.SubmitErr(func() (string, error) {
		return "success", nil
	})

	failTask := errPool.SubmitErr(func() (string, error) {
		return "", errors.New("task failed")
	})

	result, err := successTask.Wait()
	fmt.Printf("Success task: %s, err: %v\n", result, err)

	result, err = failTask.Wait()
	fmt.Printf("Fail task: %s, err: %v\n", result, err)
	errPool.StopAndWait()

	// Get pool statistics
	statsPool := pond.NewPool(5)
	for i := 0; i < 20; i++ {
		statsPool.Submit(func() {
			time.Sleep(10 * time.Millisecond)
		})
	}
	time.Sleep(50 * time.Millisecond)

	fmt.Printf("Running workers: %d\n", statsPool.RunningWorkers())
	fmt.Printf("Submitted tasks: %d\n", statsPool.SubmittedTasks())
	fmt.Printf("Completed tasks: %d\n", statsPool.CompletedTasks())

	statsPool.StopAndWait()

	// Pool with max capacity (backpressure)
	boundedPool := pond.NewPool(2, pond.WithMaxCapacity(5))
	for i := 0; i < 10; i++ {
		i := i
		// Submit blocks when queue is full
		boundedPool.Submit(func() {
			fmt.Printf("Bounded task %d\n", i)
			time.Sleep(20 * time.Millisecond)
		})
	}
	boundedPool.StopAndWait()
}
