package api

import (
	"encoding/json"
	"log"
	"net/http"
	"time"

	"gorm.io/gorm"
)

type Purchase struct {
	gorm.Model    `json:"-"`
	TransactionID int     `json:"-" gorm:"column:transaction"`
	ProductCode   int     `json:"code" gorm:"column:product"`
	Product       Product `json:"product" gorm:"foreignKey:ProductCode;references:Code"`
	Price         int     `json:"price"`
	Ammount       int     `json:"ammount"`
}

func (a *api) AddPurchase(num int, w http.ResponseWriter, req *http.Request) {
	var purchase []Purchase
	err := json.NewDecoder(req.Body).Decode(&purchase)
	if err != nil {
		log.Printf("Can't create purchase: %v", err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	total := 0
	for i, p := range purchase {
		var product Product
		err = a.db.Where("code = ?", p.ProductCode).First(&product).Error
		if err != nil {
			log.Printf("Can't get product %d: %v", p.ProductCode, err)
			w.WriteHeader(http.StatusNotAcceptable)
			return
		}

		total += product.Price * p.Ammount
		purchase[i].Price = product.Price
	}
	if total == 0 {
		log.Printf("Empty purchase (%d)", num)
		w.WriteHeader(http.StatusNotAcceptable)
		return
	}

	httpStatus := a.substractMemberBalance(num, total)
	if httpStatus != http.StatusOK {
		w.WriteHeader(httpStatus)
		return
	}

	transaction := Transaction{
		MemberNum: num,
		Date:      time.Now(),
		Purchase:  purchase,
		Type:      "purchase",
		Total:     total,
	}
	err = a.db.Create(&transaction).Error
	if err != nil {
		log.Printf("Can't create purchase: %v\n%v", err, purchase)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	for _, p := range purchase {
		err := a.db.Model(&Product{}).
			Where("code = ?", p.ProductCode).
			Update("stock", gorm.Expr("stock - ?", p.Ammount)).Error
		if err != nil {
			log.Printf("Can't update product stock %d-%d: %v", p.ProductCode, p.Ammount, err)
		}
	}

	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusCreated)
	err = json.NewEncoder(w).Encode(transaction)
	if err != nil {
		log.Printf("Can't encode added purchase: %v", err)
		w.WriteHeader(http.StatusInternalServerError)
	}

}

func (a *api) substractMemberBalance(num int, total int) int {
	var member Member
	err := a.db.Where("num = ?", num).Find(&member).Error
	if err != nil {
		log.Printf("Can't find member %d: %v", num, err)
		return http.StatusNotAcceptable
	}
	if member.Balance < total {
		log.Printf("Member %d don't have enough money (%d-%d)", num, member.Balance, total)
		return http.StatusBadRequest
	}
	err = a.db.Model(&Member{}).
		Where("num = ?", num).
		Update("balance", gorm.Expr("balance - ?", total)).Error
	if err != nil {
		log.Printf("Can't update update member balance %d-%d: %v", num, total, err)
		return http.StatusNotAcceptable
	}
	return http.StatusOK
}