package mocks

import (
	"context"
	"errors"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/request"
	"github.com/aws/aws-sdk-go/service/sns"
	"github.com/aws/aws-sdk-go/service/sns/snsiface"
	"github.com/stretchr/testify/mock"
)

const (
	SNSCreateTopic               = "sns-create-topic"
	SNSGetTopicAttributes        = "sns-get-topic-attributes"
	SNSSetTopicAttributes        = "sns-set-topic-attributes"
	SNSAddPermission             = "sns-add-permission"
	SNSRemovePermission          = "sns-remove-permission"
	SNSGetSubscriptionAttributes = "sns-get-subscription-attributes"
	SNSSubscribe                 = "sns-subscribe"
	SNSUnsubscribe               = "sns-unsubscribe"
)

type MockSNS struct {
	mock.Mock
	snsiface.SNSAPI
}

func NewMockSNS() *MockSNS {
	m := &MockSNS{}
	// Layout various canned error behaviors
	m.On("CreateTopicWithContext", mock.MatchedBy(IsBehavior(SNSCreateTopic, Error)), mock.Anything, mock.Anything).Return((*sns.CreateTopicOutput)(nil), errors.New(Error))
	m.On("GetTopicAttributesWithContext", mock.MatchedBy(IsBehavior(SNSGetTopicAttributes, Error)), mock.Anything, mock.Anything).Return(nil, errors.New(Error))
	m.On("SetTopicAttributesWithContext", mock.MatchedBy(IsBehavior(SNSSetTopicAttributes, Error)), mock.Anything, mock.Anything).Return(nil, errors.New(Error))
	m.On("AddPermissionWithContext", mock.MatchedBy(IsBehavior(SNSAddPermission, Error)), mock.Anything, mock.Anything).Return(nil, errors.New(Error))
	m.On("RemovePermissionWithContext", mock.MatchedBy(IsBehavior(SNSRemovePermission, Error)), mock.Anything, mock.Anything).Return(nil, errors.New(Error))
	m.On("GetSubscriptionAttributesWithContext", mock.MatchedBy(IsBehavior(SNSGetSubscriptionAttributes, Error)), mock.Anything, mock.Anything).Return(nil, errors.New(Error))
	m.On("SubscribeWithContext", mock.MatchedBy(IsBehavior(SNSSubscribe, Error)), mock.Anything, mock.Anything).Return(nil, errors.New(Error))
	m.On("UnsubscribeWithContext", mock.MatchedBy(IsBehavior(SNSUnsubscribe, Error)), mock.Anything, mock.Anything).Return(nil, errors.New(Error))

	return m
}

func (m *MockSNS) CreateTopicWithContext(ctx aws.Context, v *sns.CreateTopicInput, opts ...request.Option) (*sns.CreateTopicOutput, error) {
	args := m.Called(ctx, v, opts)
	return args.Get(0).(*sns.CreateTopicOutput), args.Error(1)
}

func (m *MockSNS) GetTopicAttributesWithContext(ctx context.Context, in *sns.GetTopicAttributesInput, opts ...request.Option) (*sns.GetTopicAttributesOutput, error) {
	args := m.Called(ctx, in, opts)
	if args.Get(0) == nil {
		return nil, args.Error(1)
	}
	return args.Get(0).(*sns.GetTopicAttributesOutput), args.Error(1)
}

func (m *MockSNS) SetTopicAttributesWithContext(ctx context.Context, in *sns.SetTopicAttributesInput, opts ...request.Option) (*sns.SetTopicAttributesOutput, error) {
	args := m.Called(ctx, in, opts)
	if args.Get(0) == nil {
		return nil, args.Error(1)
	}
	return args.Get(0).(*sns.SetTopicAttributesOutput), args.Error(1)
}

func (m *MockSNS) AddPermissionWithContext(ctx context.Context, in *sns.AddPermissionInput, opts ...request.Option) (*sns.AddPermissionOutput, error) {
	args := m.Called(ctx, in, opts)
	if args.Get(0) == nil {
		return nil, args.Error(1)
	}
	return args.Get(0).(*sns.AddPermissionOutput), args.Error(1)
}

func (m *MockSNS) GetSubscriptionAttributesWithContext(ctx context.Context, in *sns.GetSubscriptionAttributesInput, opts ...request.Option) (*sns.GetSubscriptionAttributesOutput, error) {
	args := m.Called(ctx, in, opts)
	if args.Get(0) == nil {
		return nil, args.Error(1)
	}
	return args.Get(0).(*sns.GetSubscriptionAttributesOutput), args.Error(1)
}

func (m *MockSNS) SubscribeWithContext(ctx context.Context, in *sns.SubscribeInput, opts ...request.Option) (*sns.SubscribeOutput, error) {
	args := m.Called(ctx, in, opts)
	if args.Get(0) == nil {
		return nil, args.Error(1)
	}
	return args.Get(0).(*sns.SubscribeOutput), args.Error(1)
}

func (m *MockSNS) UnsubscribeWithContext(ctx context.Context, in *sns.UnsubscribeInput, opts ...request.Option) (*sns.UnsubscribeOutput, error) {
	args := m.Called(ctx, in, opts)
	if args.Get(0) == nil {
		return nil, args.Error(1)
	}
	return args.Get(0).(*sns.UnsubscribeOutput), args.Error(1)
}

func (m *MockSNS) RemovePermissionWithContext(ctx context.Context, in *sns.RemovePermissionInput, opts ...request.Option) (*sns.RemovePermissionOutput, error) {
	args := m.Called(ctx, in, opts)
	if args.Get(0) == nil {
		return nil, args.Error(1)
	}
	return args.Get(0).(*sns.RemovePermissionOutput), args.Error(1)
}
