package api

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

	"git.sp4ke.com/sp4ke/bit4sat/db"
	"git.sp4ke.com/sp4ke/bit4sat/ln"
	"git.sp4ke.com/sp4ke/bit4sat/storage"
	"git.sp4ke.com/sp4ke/bit4sat/utils"
	"github.com/gin-gonic/gin"
	"github.com/mediocregopher/radix/v3"
)

func upSessionHandler(c *gin.Context) {

	upSession, err := SessionStore.Get(c.Request, UpSessionKey)
	if err != nil {
		utils.JSONErrPriv(c, http.StatusInternalServerError, err)
		return
	}

	lastUp, exists := upSession.Values["lastUp"]

	if exists {

		err = upSession.Save(c.Request, c.Writer)
		if err != nil {
			utils.JSONErrPriv(c, http.StatusInternalServerError, err)
			return
		}

		// Get upload status

		uId := lastUp.([]string)[0]

		key := fmt.Sprintf("upload_status_%s", uId)

		var upStatus storage.UpStatus
		err := db.DB.Redis.Do(radix.FlatCmd(&upStatus, "GET", key))
		if err != nil {
			utils.JSONErrPriv(c, http.StatusInternalServerError,
				fmt.Errorf("error finding upload status %s", lastUp))
			fmt.Println(err)
			return
		}

		invoice, err := storage.GetUploadInvoice(lastUp.(string))
		if err != nil {
			utils.JSONErrPriv(c, http.StatusInternalServerError, err)
			return
		}

		// if invoice is not empty
		c.JSON(http.StatusOK, gin.H{
			"uploadId": lastUp,
			"status":   upStatus,
			"invoice":  invoice,
		})
		return

	}

	c.JSON(http.StatusOK, gin.H{
		"uploadId": 0,
	})
	return
}

func pollInvoice(c *gin.Context) {
	invoiceId := c.Param("rhash")

	// First check if already paid

	// Get the invoice from invoice_id
	invoiceKey := fmt.Sprintf("invoice_%s", invoiceId)
	invoice := ln.Invoice{}
	err := db.DB.Redis.Do(radix.FlatCmd(&invoice, "GET", invoiceKey))
	if err != nil {
		utils.JSONErrPriv(c, http.StatusInternalServerError, err)
		return
	}

	// If paid return ok
	if invoice.Settled {
		c.JSON(http.StatusOK, gin.H{
			"invoice": invoice,
		})

		// Poll
	} else {

		invoiceChan := make(chan *ln.Invoice)
		errorChan := make(chan error)

		log.Printf("starting invoice poll for %s", invoice.RHash)
		// If waiting payment, wait until invoice is paid
		go ln.PollPaidInvoice(invoice.RHash, invoiceChan, errorChan)
		select {
		case invoice := <-invoiceChan:

			// if expired return with expired response
			if invoice.Expired {

				c.JSON(http.StatusGone, gin.H{
					"invoice": invoice,
				})

				return
			}

			////////////////
			///// Invoice was paid
			////////////////
			//
			log.Println("POLL: invoice was paid")

			c.JSON(http.StatusOK, gin.H{
				"invoice": invoice,
			})
			return

		case err := <-errorChan:
			utils.JSONErrPriv(c, http.StatusInternalServerError, err)
			return
		}

		// We stopped waiting for the invoice, it must have expired
		c.JSON(http.StatusGone, gin.H{
			"invoice": invoice,
		})
		return

	}
}

// Was used by ln-charge
func invoiceCbHandler(c *gin.Context) {
	invoice := ln.Invoice{}

	//dec := json.Decoder(c.Request.Body)

	if err := c.ShouldBindJSON(&invoice); err != nil {
		log.Println(err)
		utils.JSONErr(c, http.StatusNotAcceptable,
			"callback: could not parse request from charge api")
		return
	}

	log.Printf("received invoice paid from ln charge\n%s", invoice)
	c.Status(http.StatusOK)

	// get upload id related to invoice
	var uploadId string
	invoiceUploadKey := fmt.Sprintf("invoice_%s_upload_id", invoice.RHash)

	err := db.DB.Redis.Do(radix.FlatCmd(&uploadId, "GET", invoiceUploadKey))
	if err != nil {
		panic(err)
	}
	if uploadId == "" {
		log.Printf("cannot find uploadId for invoice %s", invoice)
		return
	}

	// Invoice paid !!!!

	// Set upload status to paid
	err = storage.SetUploadStatus(uploadId, storage.UpPaid)
	if err != nil {
		panic(err)
	}
	//
	// Update Upload Invoice
	err = storage.SetUploadInvoice(uploadId, &invoice)
	if err != nil {
		panic(err)
	}

	return
}
