package main

import (
	"context"
	"errors"
	"fmt"
	"sync"
	"sync/atomic"

	"golang.org/x/sync/errgroup"
	"golang.org/x/sync/semaphore"
	"golang.org/x/sync/singleflight"
)

func GroupFailure() error {
	g, ctx := errgroup.WithContext(context.Background())
	started := make(chan struct{})
	g.Go(func() error { close(started); <-ctx.Done(); return ctx.Err() })
	g.Go(func() error { <-started; return errors.New("upstream failed") })
	return g.Wait()
}
func SharedLoad() (int64, bool) {
	var g singleflight.Group
	var calls atomic.Int64
	gate := make(chan struct{})
	fn := func() (any, error) { calls.Add(1); <-gate; return "value", nil }
	a := g.DoChan("key", fn)
	b := g.DoChan("key", fn)
	close(gate)
	x, y := <-a, <-b
	return calls.Load(), x.Shared && y.Shared && x.Err == nil && y.Err == nil
}
func WeightedWork(ctx context.Context, limit int64, weights []int64) (int64, error) {
	if limit <= 0 {
		return 0, errors.New("limit must be positive")
	}
	// Validate before launching any work.
	for _, n := range weights {
		if n <= 0 || n > limit {
			return 0, errors.New("invalid weight")
		}
	}
	sem := semaphore.NewWeighted(limit)
	var wg sync.WaitGroup
	var current, peak atomic.Int64
	var acquireErr error
	for _, n := range weights {
		if err := sem.Acquire(ctx, n); err != nil {
			acquireErr = err
			break
		}
		wg.Add(1)
		go func(weight int64) {
			defer wg.Done()
			defer sem.Release(weight)
			now := current.Add(weight)
			for {
				old := peak.Load()
				if now <= old || peak.CompareAndSwap(old, now) {
					break
				}
			}
			// Real work belongs here and must honor ctx independently.
			current.Add(-weight)
		}(n)
	}
	wg.Wait()
	return peak.Load(), acquireErr
}
func NotACache() int {
	var g singleflight.Group
	calls := 0
	f := func() (any, error) { calls++; return "value", nil }
	g.Do("key", f)
	g.Do("key", f)
	return calls
}
func TryGoAtCapacity() bool {
	var g errgroup.Group
	g.SetLimit(1)
	release := make(chan struct{})
	g.Go(func() error { <-release; return nil })
	started := g.TryGo(func() error { return nil })
	close(release)
	if err := g.Wait(); err != nil {
		panic(err)
	}
	return started
}
func main() {
	fmt.Println("errgroup:", GroupFailure())
	fmt.Println("trygo at capacity:", TryGoAtCapacity())
	calls, shared := SharedLoad()
	fmt.Println("singleflight calls:", calls, "shared:", shared)
	fmt.Println("sequential calls:", NotACache())
	peak, err := WeightedWork(context.Background(), 3, []int64{2, 1, 2, 1})
	fmt.Println("semaphore within limit:", peak <= 3, err)
}
