package main

import (
	"context"
	"errors"
	"sync"
	"sync/atomic"
	"testing"
	"time"
)

func TestCanceledQueuedJobAndShutdown(t *testing.T) {
	p := NewPool(1, 1)
	start := make(chan struct{})
	release := make(chan struct{})
	first, err := p.TrySubmit(context.Background(), func(context.Context) error { close(start); <-release; return nil })
	if err != nil {
		t.Fatal(err)
	}
	<-start
	ctx, cancel := context.WithCancel(context.Background())
	var ran atomic.Bool
	result, err := p.TrySubmit(ctx, func(context.Context) error { ran.Store(true); return nil })
	if err != nil {
		t.Fatal(err)
	}
	cancel()
	short, stop := context.WithCancel(context.Background())
	stop()
	if err := p.Shutdown(short); !errors.Is(err, context.Canceled) {
		t.Fatal(err)
	}
	if _, err := p.TrySubmit(context.Background(), func(context.Context) error { return nil }); !errors.Is(err, ErrClosed) {
		t.Fatal(err)
	}
	close(release)
	<-first
	if err := <-result; !errors.Is(err, context.Canceled) || ran.Load() {
		t.Fatal(err, ran.Load())
	}
	deadline, done := context.WithTimeout(context.Background(), time.Second)
	defer done()
	if err := p.Shutdown(deadline); err != nil {
		t.Fatal(err)
	}
}
func TestConcurrentCloseSubmit(t *testing.T) {
	p := NewPool(2, 4)
	var wg sync.WaitGroup
	for range 100 {
		wg.Go(func() { _, _ = p.TrySubmit(context.Background(), func(context.Context) error { return nil }) })
	}
	wg.Go(func() { _ = p.Shutdown(context.Background()) })
	wg.Wait()
	if err := p.Shutdown(context.Background()); err != nil {
		t.Fatal(err)
	}
}
func TestBatchOwnsCopiesAndFlushesTail(t *testing.T) {
	xs := []int{1, 2, 3}
	got := Batch(xs, 2)
	xs[0] = 99
	if len(got) != 2 || len(got[1]) != 1 || got[0][0] != 1 {
		t.Fatal(got)
	}
}
