package main

import (
	"context"
	"encoding/json"
	"errors"
	"testing"
	"time"

	"code.justin.tv/foundation/history-service/internal/awsmocks"
	"code.justin.tv/foundation/history-service/internal/gdpr/gdprmocks"
	"code.justin.tv/foundation/history-service/internal/queue"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/sqs"
	"github.com/stretchr/testify/suite"
)

type DeleteAuditsSuite struct {
	suite.Suite
	mockedGdprClient *gdprmocks.ClientAPI
	mockedQueue      *awsmocks.SQSAPI
	deleteAudits     *deleteAudits
}

func (s *DeleteAuditsSuite) SetupTest() {
	s.mockedGdprClient = new(gdprmocks.ClientAPI)
	s.mockedQueue = new(awsmocks.SQSAPI)
	s.deleteAudits = &deleteAudits{
		queue:      s.mockedQueue,
		gdprClient: s.mockedGdprClient,
		queueURL:   "fakeQueueURL",
	}
}
func (s *DeleteAuditsSuite) TeardownTest() {
	s.mockedGdprClient.AssertExpectations(s.T())
	s.mockedQueue.AssertExpectations(s.T())
}

func (s *DeleteAuditsSuite) TestDeleteAuditsNoMessage() {

	ctx := context.Background()
	s.mockedQueue.On("ReceiveMessageWithContext", ctx, &sqs.ReceiveMessageInput{
		QueueUrl:            aws.String(s.deleteAudits.queueURL),
		MaxNumberOfMessages: aws.Int64(1),
		WaitTimeSeconds:     aws.Int64(20),
	}).Return(&sqs.ReceiveMessageOutput{}, nil)

	err := s.deleteAudits.DeleteWithContext(ctx)
	s.Assert().NoError(err)
}

func (s *DeleteAuditsSuite) TestDeleteAuditsQueueError() {

	ctx := context.Background()
	queueURL := "fakeQueueURL"
	s.mockedQueue.On("ReceiveMessageWithContext", ctx, &sqs.ReceiveMessageInput{
		QueueUrl:            aws.String(queueURL),
		MaxNumberOfMessages: aws.Int64(1),
		WaitTimeSeconds:     aws.Int64(20),
	}).Return(nil, errors.New("someFakeError"))

	err := s.deleteAudits.DeleteWithContext(ctx)
	s.Assert().Error(err)
}

func (s *DeleteAuditsSuite) TestDeleteAuditsGDPRClientError() {

	ctx := context.Background()
	queueURL := "fakeQueueURL"
	output := s.buildFakeQueueMessage("123", time.Now().UnixNano())
	s.mockedQueue.On("ReceiveMessageWithContext", ctx, &sqs.ReceiveMessageInput{
		QueueUrl:            aws.String(queueURL),
		MaxNumberOfMessages: aws.Int64(1),
		WaitTimeSeconds:     aws.Int64(20),
	}).Return(output, nil)

	s.mockedGdprClient.On("DeleteAudits", ctx, "123").Return(errors.New("gdpr client failed"))
	err := s.deleteAudits.DeleteWithContext(ctx)
	s.Assert().Error(err)
}

func (s *DeleteAuditsSuite) TestDeleteAuditsOneMessage() {

	ctx := context.Background()
	queueURL := "fakeQueueURL"

	output := s.buildFakeQueueMessage("123", time.Now().UnixNano())
	s.mockedQueue.On("ReceiveMessageWithContext", ctx, &sqs.ReceiveMessageInput{
		QueueUrl:            aws.String(queueURL),
		MaxNumberOfMessages: aws.Int64(1),
		WaitTimeSeconds:     aws.Int64(20),
	}).Return(output, nil).Return(&sqs.ReceiveMessageOutput{}, nil)

	s.mockedQueue.On("DeleteMessageWithContext", ctx, &sqs.DeleteMessageInput{
		QueueUrl:      aws.String(queueURL),
		ReceiptHandle: aws.String("handle"),
	}).Return(&sqs.DeleteMessageOutput{}, nil)

	s.mockedGdprClient.On("DeleteAudits", ctx, "123").Return(nil)
	err := s.deleteAudits.DeleteWithContext(ctx)
	s.Assert().NoError(err)
}

func (s *DeleteAuditsSuite) TestDeleteAuditsMultipleMessage() {

	ctx := context.Background()
	queueURL := "fakeQueueURL"

	output := s.buildFakeQueueMessage("123", time.Now().UnixNano())
	s.mockedQueue.On("ReceiveMessageWithContext", ctx, &sqs.ReceiveMessageInput{
		QueueUrl:            aws.String(queueURL),
		MaxNumberOfMessages: aws.Int64(1),
		WaitTimeSeconds:     aws.Int64(20),
	}).Return(output, nil).
		Return(output, nil).
		Return(output, nil).
		Return(output, nil).
		Return(&sqs.ReceiveMessageOutput{}, nil)

	s.mockedQueue.On("DeleteMessageWithContext", ctx, &sqs.DeleteMessageInput{
		QueueUrl:      aws.String(queueURL),
		ReceiptHandle: aws.String("handle"),
	}).Return(&sqs.DeleteMessageOutput{}, nil)

	s.mockedGdprClient.On("DeleteAudits", ctx, "123").Return(nil)
	err := s.deleteAudits.DeleteWithContext(ctx)
	s.Assert().NoError(err)
}

func (s *DeleteAuditsSuite) buildFakeQueueMessage(userID string, timestamp int64) *sqs.ReceiveMessageOutput {
	queueMessage := queue.DeleteUserMessage{
		UserID:    userID,
		Timestamp: time.Now(),
	}
	m, err := json.Marshal(queueMessage)
	if err != nil {
		s.Require().NoError(err)
	}

	return &sqs.ReceiveMessageOutput{
		Messages: []*sqs.Message{
			{
				Body:          aws.String(string(m)),
				ReceiptHandle: aws.String("handle"),
			},
		},
	}
}

func TestECSTaskDeleteUserAudits(t *testing.T) {
	suite.Run(t, new(DeleteAuditsSuite))
}
