package sqspoller

import (
	"strconv"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/sqs"
)

// Ack signals we want to acknowledge a message as being complete.
func (c *SQSPoller) Ack(receiptHandle string) {
	c.acks <- receiptHandle
}

func (c *SQSPoller) ackHub() {
	toAck := make([]string, 0, maxIdsPerBatchDelete)
	ticker := time.NewTicker(minAckFrequency)
	defer ticker.Stop()

	batch := func() {
		if len(toAck) != 0 {
			tmp := make([]string, len(toAck))
			copy(tmp, toAck)
			toAck = toAck[:0]
			runTask(&c.hubGroup, func() {
				c.doAcks(tmp)
			})
		}
	}

	for {
		select {
		case handle, ok := <-c.acks:
			if ok {
				toAck = append(toAck, handle)
				if len(toAck) == maxIdsPerBatchDelete {
					batch()
				}
			} else {
				batch()
				return
			}
		case <-ticker.C:
			batch()
		}
	}
}

func (c *SQSPoller) doAcks(receiptHandles []string) {
	req := &sqs.DeleteMessageBatchInput{
		QueueUrl: aws.String(c.url),
	}
	idToHandle := make(map[string]string)
	for i, handle := range receiptHandles {
		id := "m" + strconv.Itoa(i)
		idToHandle[id] = handle
		req.Entries = append(req.Entries, &sqs.DeleteMessageBatchRequestEntry{
			Id:            aws.String(id),
			ReceiptHandle: aws.String(handle),
		})
	}

	result, err := c.client.DeleteMessageBatchWithContext(c.stopRequests.Context, req)

	if err != nil {
		c.callback(&HookEventAckError{
			Request:        req,
			Err:            err,
			ReceiptHandles: receiptHandles,
		})

		// XXX(EDGEPLAT-1900): Maybe some codes are unrecoverable and re-queueing is a bad idea?
		for _, handle := range receiptHandles {
			c.acks <- handle
		}

	} else if len(result.Failed) != 0 {
		// TODO(EDGEPLAT-1900): figure out if there's a listing of codes that would allow us to know what happened

		failedHandles := make([]string, len(result.Failed))
		for i, failed := range result.Failed {
			handle := idToHandle[*failed.Id]
			failedHandles[i] = handle
		}

		c.callback(&HookEventAckPartialFail{
			Request:       req,
			Result:        result,
			FailedHandles: failedHandles,
		})
	}
}
