package workqueue

import (
	"context"
	"fmt"
	"sync"
	"testing"

	"github.com/google/go-cmp/cmp"
)

func TestSerializer(t *testing.T) {
	var cases = []struct {
		source   int
		perBatch int
	}{
		{
			source:   1000,
			perBatch: 1,
		},
		{
			source:   1000,
			perBatch: 10,
		},
		{
			source:   1000,
			perBatch: 100,
		},
		{
			source:   999,
			perBatch: 13,
		},
	}

	for _, c := range cases {
		t.Run(fmt.Sprintf("source=%d,perBatch=%d", c.source, c.perBatch), func(t *testing.T) {
			sources := make([]int32, c.source)
			for i := range sources {
				sources[i] = int32(i)
			}

			p := NewSerializer(sources, c.perBatch)

			got := make(map[int32]bool)
			p.Do(context.Background(), func(_ context.Context, job []int32) {
				for _, j := range job {
					got[j] = true
				}
			})

			want := make(map[int32]bool)
			for _, i := range sources {
				want[i] = true
			}

			if diff := cmp.Diff(want, got); diff != "" {
				t.Errorf("bad number of visits (-want,+got):\n%s", diff)
			}
		})
	}
}

func TestParallelizer(t *testing.T) {
	var cases = []struct {
		source      int
		perBatch    int
		concurrency int
	}{
		{
			source:      1000,
			perBatch:    1,
			concurrency: 10,
		},
		{
			source:      1000,
			perBatch:    10,
			concurrency: 10,
		},
		{
			source:      1000,
			perBatch:    100,
			concurrency: 10,
		},
		{
			source:      999,
			perBatch:    13,
			concurrency: 10,
		},
	}

	for _, c := range cases {
		t.Run(fmt.Sprintf("source=%d,perBatch=%d,concurrency=%d", c.source, c.perBatch, c.concurrency), func(t *testing.T) {
			sources := make([]int32, c.source)
			for i := range sources {
				sources[i] = int32(i)
			}

			p := NewParallelizer(sources, c.concurrency, c.perBatch)

			mu := sync.Mutex{}
			got := make(map[int32]bool)
			p.Do(context.Background(), func(_ context.Context, job []int32) {
				for _, j := range job {
					mu.Lock()
					got[j] = true
					mu.Unlock()
				}
			})

			want := make(map[int32]bool)
			for _, i := range sources {
				want[i] = true
			}

			if diff := cmp.Diff(want, got); diff != "" {
				t.Errorf("bad number of visits (-want,+got):\n%s", diff)
			}
		})
	}
}
