package web

import (
	"fmt"
	"log"
	"net/http"

	"github.com/gin-contrib/sessions"
	"github.com/gin-gonic/gin"

	"code.osinet.fr/fgm/sqs_demo/back/services/redriver"
)

func makeRedriveHandler(rd redriver.Redriver, ms redriver.MessageStore) gin.HandlerFunc {
	return func(c *gin.Context) {
		req := c.Request
		ctx := req.Context()
		qName := c.Param("name")
		redirect := "/queue/" + qName

		sess := sessions.Default(c)
		// Do not consume sess.Flashes(): this is a redirect-only handler, and they would be lost.
		defer func() {
			_ = sess.Save()
			c.Redirect(http.StatusSeeOther, redirect)
		}()

		var (
			messages []redriver.Message
			done     bool
		)
		if messages, done = messagesFromRequest(req, qName, sess, ms); done {
			return
		}

		var flash string
		if err := rd.RedriveItems(ctx, qName, messages); err != nil {
			flash = fmt.Sprintf("failed redriving selected messages on queue %q: %v",
				qName, err)
		} else {
			flash = fmt.Sprintf("%d messages redriven to queue %q."+
				`They now carry new MessageIDs and their past MessageID will be visible in the "previous-message-id" attribute`,
				len(messages), qName)
		}
		log.Print(flash)
		sess.AddFlash(flash)
	}
}

func messagesFromRequest(req *http.Request, qName string, sess sessions.Session, ms redriver.MessageStore) ([]redriver.Message, bool) {
	if err := req.ParseForm(); err != nil {
		log.Printf("Failed to parse deletion confirm form for queue %s: %v",
			qName, err)
		sess.AddFlash(fmt.Sprintf("Failed to parsed deletion confirmm form for queue %s",
			qName))
		return nil, true
	}
	ids := parseIDs(req.Form, validateUint)

	var messages []redriver.Message
	if len(ids) == 0 {
		flash := fmt.Sprintf("Got no message to delete from queue %q", qName)
		log.Print(flash)
		sess.AddFlash(flash)
		return nil, true
	}
	messages = parseMessages(req.Form, ids)
	for i, message := range messages {
		m, ok := ms.Get(message.ReceiptHandle)
		if !ok {
			sess.AddFlash(fmt.Sprintf("Failed retrieving message with ID %s and receipt handle %s from queue %q. Aborting redrive.",
				message.MessageId, message.ReceiptHandle, qName))
			return nil, true
		}
		messages[i] = m
	}
	return messages, false
}
