package tieventbus

import (
	"context"
	"fmt"
	"testing"

	"github.com/ThreeDotsLabs/watermill/message"
	"github.com/ThreeDotsLabs/watermill/pubsub/gochannel"
	"github.com/stretchr/testify/suite"
)

type MiddlewareTestSuite struct {
	suite.Suite
}

func (*MiddlewareTestSuite) SetupTest() {
}

func TestMiddleware(t *testing.T) {
	suite.Run(t, new(MiddlewareTestSuite))
}

func (s *MiddlewareTestSuite) Test_errorAsPanicMiddleware() {
	assert := s.Assert()
	assert.Panics(func() {
		_, _ = errorAsPanicMiddleware(func(msg *message.Message) ([]*message.Message, error) {
			return nil, fmt.Errorf("test")
		})(&message.Message{})
	})
}

func (s *MiddlewareTestSuite) Test_handlerCalledMiddleware() {
	assert := s.Assert()
	ch := make(chan bool)
	middleware := handlerCalledMiddleware(ch)
	go func() {
		_, _ = middleware(func(msg *message.Message) ([]*message.Message, error) {
			return nil, nil
		})(&message.Message{})
	}()
	assert.True(<-ch)
	go func() {
		_, _ = middleware(func(msg *message.Message) ([]*message.Message, error) {
			return nil, fmt.Errorf("test")
		})(&message.Message{})
	}()
	assert.False(<-ch)
}

func (s *MiddlewareTestSuite) Test_retryMiddleware() {
	assert := s.Assert()
	for retryTimes := uint(0); retryTimes <= 3; retryTimes++ {
		called := uint(0)
		middleware := retryMiddleware(retryTimes)
		_, _ = middleware(func(msg *message.Message) ([]*message.Message, error) {
			called++
			return nil, fmt.Errorf("1")
		})(&message.Message{})
		assert.Equal(retryTimes+1, called)
	}
}

func (s *MiddlewareTestSuite) Test_deadLetterQueueMiddleware() {
	assert := s.Assert()
	ch := gochannel.NewGoChannel(gochannel.Config{Persistent: false}, nil)
	eventID := "1"
	eventType := "1"
	middleware, err := deadLetterQueueMiddleware(ch, HandlerConfig{EventType: eventType, Group: "1"})
	assert.NoError(err)
	go func() {
		_, _ = middleware(func(msg *message.Message) ([]*message.Message, error) {
			return nil, fmt.Errorf("!")
		})(message.NewMessage(eventID, []byte{}))
	}()
	msgCh, err := ch.Subscribe(context.Background(), getDLQTopic(eventType))
	assert.NoError(err)
	msg := <-msgCh
	assert.Equal(eventID, msg.UUID)
}
