package sqsclient

import (
	"fmt"
	"log"

	"code.justin.tv/eventbus/client/internal/sqspoller"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/sqs"
)

// HookEvent encapsulates both informational and error messages coming out of the SQS poller.
// It's provided for logging of lifecycle events during the running of the poller.
type HookEvent interface {
	// All HookEvents try to convert themselves to string in a logger-friendly way.
	String() string

	// Error will return the error value if this message represents an error.
	// If this message is informational, Error() returns nil.
	Error() error
}

type HookEventPollError = sqspoller.HookEventPollError
type HookEventAckError = sqspoller.HookEventAckError
type HookEventAckPartialFail = sqspoller.HookEventAckPartialFail
type HookEventBatchDelivered = sqspoller.HookEventBatchDelivered

// HookEventDecodeError represents an error that happened when parsing the input payload.
// This can include: invalid SNS JSON, invalid encoding, or invalid eventbus payload.
type HookEventDecodeError struct {
	Err        error
	RawMessage *sqs.Message
}

func (h *HookEventDecodeError) String() string {
	return fmt.Sprintf(
		"Decoding message %#v: %s",
		aws.StringValue(h.RawMessage.MessageId), h.Err.Error(),
	)
}

func (h *HookEventDecodeError) Error() error {
	return h.Err
}

// HookEventDispatchError signals errors returned from Dispatch.
type HookEventDispatchError struct {
	Err        error
	RawMessage *sqs.Message
}

func (h *HookEventDispatchError) String() string {
	return fmt.Sprintf(
		"Dispatching message %#v: %s",
		aws.StringValue(h.RawMessage.MessageId), h.Err.Error(),
	)
}

func (h *HookEventDispatchError) Error() error { return h.Err }

func wrapCallback(forward func(HookEvent)) sqspoller.HookCallback {
	return func(event sqspoller.HookEvent) {
		forward(event)
	}
}

// DefaultHookCallback prints out error messages to the stdlib logger and
// does nothing with informational messages.
var DefaultHookCallback = func(event HookEvent) {
	if err := event.Error(); err != nil {
		log.Printf("[SQS poller] error: %s", event.String())
	}
}
