package examples_test

import (
	"errors"
	"fmt"
	"time"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/types"

	. "github.com/pingcap/endless/pkg/matcher"
)

var _ = Describe("CollectionMatcher", func() {
	Context("All", func() {
		It("on errors", func() {
			var (
				err0 error
				err1 error
				err2 error
			)
			err0 = errors.New("fire~")
			fmt.Printf("%+v %+v %+v\n", err0, err1, err2)
			errs := []error{err0, err1, err2}

			Expect(errs).ShouldNot(All(func() types.GomegaMatcher { return HaveOccurred() })) // NOTICE: when you write this...
			// Expect(errs).Should(All(func() types.GomegaMatcher { return Succeed() })) // it's very likely that you actually mean this. see explanation below.
		})
		// (a.1) ShouldNot All HaveOccurred    不应该全部发生 == 应该任何一个不发生 == (b.4)
		// (a.2) ShouldNot All Succeed         不应该全部不发生 == 应该任何一个发生 == (b.3)
		// (a.3) ShouldNot Any HaveOccurred    不应该任何一个发生 == 应该全部不发生 == (b.2)
		// (a.4) ShouldNot Any Succeed         不应该任何一个不发生 == 应该全部发生 == (b.1)
		// (b.1) Should All HaveOccurred       应该全部发生
		// (b.2) Should All Succeed            应该全部不发生
		// (b.3) Should Any HaveOccurred       应该任何一个发生
		// (b.4) Should Any Succeed            应该任何一个不发生

		// TODO(Ray-Eldath): pending due to semantic incompatibility against All
		PIt("with channels, per error per channel", func() {
			err0 := make(chan error)
			err1 := make(chan error)
			err2 := make(chan error)
			errs := []chan error{err0, err1, err2}

			go func() {
				time.Sleep(50 * time.Millisecond)
				err0 <- nil
				close(err0)
			}()
			go func() {
				time.Sleep(50 * time.Millisecond)
				// err1 <- nil
				err1 <- errors.New("fire~")
				close(err1)
			}()
			go func() {
				time.Sleep(50 * time.Millisecond)
				err2 <- nil
				close(err2)
			}()

			// Eventually(errs).ShouldNot(Any(func() types.GomegaMatcher { return Receive(Succeed()) })) // Receive is used as HaveOccurred
			Consistently(errs).Should(All(func() types.GomegaMatcher { return Receive(Succeed()) }))
		})
	})
	Context("Any", func() {
		It("on many but not all nil", func() {
			var (
				err0 error
				err1 error
				err2 error
			)
			err0 = errors.New("fire~")
			err1 = errors.New("fire~~")
			// err2 = errors.New("fire~~~")
			fmt.Printf("%+v %+v %+v\n", err0, err1, err2)
			errs := []error{err0, err1, err2}

			Expect(errs).Should(Any(func() types.GomegaMatcher { return Succeed() }))
		})
	})

	Context("just Receive", func() {
		It("listen on channel", func() {
			b := make(chan bool)

			Consistently(b).ShouldNot(Receive())

			go func() {
				time.Sleep(50 * time.Millisecond)
				b <- true
			}()

			Eventually(b).Should(Receive())
		})
	})
})
