package controllers

import (
	"fmt"
	"net/http"
	"strconv"

	"git.dynamicdiscord.de/kalipso/zineshop/models"
	"git.dynamicdiscord.de/kalipso/zineshop/repositories"
	"github.com/gin-gonic/gin"
)

type PrintController interface {
	PrintVariantView(*gin.Context)
	PrintCartView(*gin.Context)
	PrintOrderView(*gin.Context)
	PrintHandler(*gin.Context)
}

type printController struct{}

func NewPrintController() PrintController {
	return &printController{}
}

func (rc *printController) PrintVariantView(c *gin.Context) {
	variant, err := repositories.ShopItems.GetVariantById(c.Param("id"))

	if err != nil {
		c.HTML(http.StatusBadRequest, "error.html", gin.H{"data": gin.H{"error": err}})
		return
	}

	shopItem, err := repositories.ShopItems.GetById(fmt.Sprintf("%v", variant.ShopItemID))

	if err != nil {
		c.HTML(http.StatusBadRequest, "error.html", gin.H{"data": gin.H{"error": err}})
		return
	}

	type ShopItemVariantPair struct {
		ShopItem    models.ShopItem
		ItemVariant models.ItemVariant
	}

	data := CreateSessionData(c, gin.H{
		"itemVariants": []ShopItemVariantPair{
			{ShopItem: shopItem, ItemVariant: variant},
		},
	})

	fmt.Println(data)

	c.HTML(http.StatusOK, "printvariant.html", data)
}

func (rc *printController) PrintCartView(c *gin.Context) {
	sessionId := GetSessionId(c)

	cartItems, err := repositories.CartItems.GetAllBySession(sessionId)
	if err != nil {
		c.HTML(http.StatusBadRequest, "error.html", gin.H{"data": gin.H{"error": err}})
		return
	}

	paper, err := repositories.Papers.GetAll()
	if err != nil {
		c.HTML(http.StatusBadRequest, "error.html", gin.H{"data": gin.H{"error": err}})
		return
	}

	data := CreateSessionData(c, gin.H{
		"paper":     paper,
		"cartItems": cartItems,
	})

	c.HTML(http.StatusOK, "printvariant.html", data)
}

func (rc *printController) PrintOrderView(c *gin.Context) {
	order, err := repositories.Orders.GetByToken(c.Param("token"))

	if err != nil {
		c.HTML(http.StatusBadRequest, "error.html", gin.H{"data": gin.H{"error": err}})
		return
	}

	paper, err := repositories.Papers.GetAll()
	if err != nil {
		c.HTML(http.StatusBadRequest, "error.html", gin.H{"data": gin.H{"error": err}})
		return
	}

	cartItems := order.CartItems

	data := CreateSessionData(c, gin.H{
		"paper":     paper,
		"cartItems": cartItems,
	})

	c.HTML(http.StatusOK, "printvariant.html", data)
}

func (rc *printController) PrintHandler(c *gin.Context) {
	variantIds := c.PostFormArray("variant-id[]")
	variantAmounts := c.PostFormArray("variant-amount[]")
	variantPapertypes := c.PostFormArray("variant-papertype[]")
	variantCoverPages := c.PostFormArray("variant-coverpage[]")

	if len(variantIds) != len(variantAmounts) || len(variantIds) != len(variantCoverPages) {
		c.HTML(http.StatusBadRequest, "error.html", gin.H{"data": gin.H{"error": "Invalid arguments"}})
		return
	}

	var printJobs []models.PrintJob
	priceTotal := 0.0
	for idx := range variantIds {
		variant, err := repositories.ShopItems.GetVariantById(variantIds[idx])

		if err != nil {
			c.HTML(http.StatusBadRequest, "error.html", gin.H{"data": gin.H{"error": err}})
			return
		}

		shopItem, err := repositories.ShopItems.GetById(fmt.Sprintf("%v", variant.ShopItemID))

		if err != nil {
			c.HTML(http.StatusBadRequest, "error.html", gin.H{"data": gin.H{"error": err}})
			return
		}

		paperType, err := repositories.Papers.GetById(fmt.Sprintf("%v", variantPapertypes[idx]))
		if err != nil {
			c.HTML(http.StatusBadRequest, "error.html", gin.H{"data": gin.H{"error": err}})
			return
		}

		var coverPage *models.Paper
		if variantCoverPages[idx] != "0" {
			coverPageTmp, err := repositories.Papers.GetById(fmt.Sprintf("%v", variantCoverPages[idx]))
			if err != nil {
				c.HTML(http.StatusBadRequest, "error.html", gin.H{"data": gin.H{"error": err}})
				return
			}

			coverPage = &coverPageTmp
		}

		variantAmount, err := strconv.Atoi(variantAmounts[idx])
		if err != nil {
			c.HTML(http.StatusBadRequest, "error.html", gin.H{"data": gin.H{"error": err}})
			return
		}

		fmt.Println("Printing Costs:")

		printJob, err := models.NewPrintJob(shopItem, variant, paperType, coverPage, uint(variantAmount))

		if err != nil {
			c.HTML(http.StatusBadRequest, "error.html", gin.H{"data": gin.H{"error": err}})
			return
		}
		printJob.CalculatePrintCosts()
		priceTotal += printJob.PriceTotal
		printJobs = append(printJobs, printJob)
	}

	invoice := models.Invoice{
		PrintJobs:     printJobs,
		PricePerClick: 0.002604,
		PartCosts:     0.0067,
		PriceTotal:    priceTotal,
	}
	invoice, err := repositories.Invoices.Create(invoice)

	if err != nil {
		c.HTML(http.StatusBadRequest, "error.html", gin.H{"data": gin.H{"error": err}})
		return
	}

	executeJobs := func() {
		for _, printJob := range printJobs {
			err := printJob.Execute()

			if err != nil {
				fmt.Printf("Error: %s\n", err)
				continue
			}

			printJob.ShopItem.WasPrinted = true
			_, err = repositories.ShopItems.Update(printJob.ShopItem)

			if err != nil {
				fmt.Printf("Error: %s\n", err)
			}
		}
	}

	go executeJobs()

	fmt.Println(invoice)
	data := CreateSessionData(c, gin.H{
		"invoice": invoice,
	})

	c.HTML(http.StatusOK, "printstarted.html", data)
}
