package api

import (
	"encoding/json"
	"fmt"
	"git.sch.bme.hu/disappointment-industries/becskasszasch/db"
	"git.sch.bme.hu/disappointment-industries/becskasszasch/helpers"
	"git.sch.bme.hu/disappointment-industries/becskasszasch/homepage"
	"net/http"
)

var router = http.NewServeMux()
var Handler = pultoschMW(router)

func init() {
	router.Handle("/product", adminMW(http.HandlerFunc(ProductHandler)))
	router.HandleFunc("/products", ProductHandler)
	router.Handle("/user", adminMW(http.HandlerFunc(UpdateUserHandler)))
	router.HandleFunc("/users", GetUsers)
	router.HandleFunc("/cart", BuyInPult)
}

func adminMW(h http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		admin, err := homepage.GetUserInfoBySession(r)
		if err != nil {
			helpers.Logger.Println(err)
			return
		}
		if admin.IsAdmin {
			h.ServeHTTP(w, r)
		} else {
			w.WriteHeader(http.StatusForbidden)
		}
	})
}

func pultoschMW(h http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		user, err := homepage.GetUserInfoBySession(r)
		if err != nil {
			helpers.Logger.Println(err)
			return
		}
		if user.IsPultosch {
			h.ServeHTTP(w, r)
		} else {
			w.WriteHeader(http.StatusForbidden)
		}
	})
}

func ProductHandler(w http.ResponseWriter, r *http.Request) {
	switch r.Method {
	case http.MethodPut:

		var product db.Product

		if err := json.NewDecoder(r.Body).Decode(&product); err != nil {
			http.Error(w, err.Error(), http.StatusBadRequest)
			return
		}

		err := product.Save()
		if err != nil {
			// TODO: handle error
			return
		}
		w.WriteHeader(http.StatusOK)

	case http.MethodPatch:
		var product db.Product

		if err := json.NewDecoder(r.Body).Decode(&product); err != nil {
			http.Error(w, err.Error(), http.StatusBadRequest)
			return
		}

		err := product.Save()
		if err != nil {
			// TODO: handle error
			return
		}
		w.WriteHeader(http.StatusOK)

	case http.MethodGet:
		var product db.Product
		id := r.URL.Query().Get("id")
		product.ID = id

		product.Load()

		json.NewEncoder(w).Encode(product)

	default:
		http.Error(w, "Invalid method", http.StatusMethodNotAllowed)
	}
}

func UpdateUserHandler(w http.ResponseWriter, r *http.Request) {
	switch r.Method {
	case http.MethodPatch:
		var user db.User

		if err := json.NewDecoder(r.Body).Decode(&user); err != nil {
			http.Error(w, err.Error(), http.StatusBadRequest)
			return
		}
		oldUser := db.User{SchAcc: user.SchAcc}
		err := oldUser.Load()
		if err != nil {
			// TODO: handle error
			return
		}
		user.Money = oldUser.Money
		user.Spends = oldUser.Spends
		user.Name = oldUser.Name

		err = user.Save()
		if err != nil {
			// TODO: handle error
			return
		}
		w.WriteHeader(http.StatusOK)

	default:
		http.Error(w, "Invalid method", http.StatusMethodNotAllowed)
	}
}

func GetUsers(w http.ResponseWriter, r *http.Request) {
	switch r.Method {
	case http.MethodGet:

		users, err := db.GetUsersSorted(db.GetDB())
		if err != nil {
			http.Error(w, err.Error(), http.StatusBadRequest)
			return
		}

		json.NewEncoder(w).Encode(users)
	}
}

func BuyInPult(w http.ResponseWriter, r *http.Request) {
	switch r.Method {
	case http.MethodPost:
		dec := json.NewDecoder(r.Body)
		var pult PultAPIData
		err := dec.Decode(&pult)
		if err != nil {
			http.Error(w, err.Error(), http.StatusBadRequest)
			return
		}

		user, err := db.GetUser(pult.UserID)
		if err != nil {
			http.Error(w, err.Error(), http.StatusBadRequest)
			return
		}

		pultosch, err := homepage.GetUserInfoBySession(r)
		if err != nil {
			http.Error(w, err.Error(), http.StatusBadRequest)
			return
		}

		var spends []*db.Spend
		for _, purchase := range pult.Purchases {
			if purchase.Amount == 0 {
				continue
			}
			spend := db.Spend{
				User:   user,
				SchAcc: user.SchAcc,
				ProdID: purchase.ProductID,
				Amount: purchase.Amount,
				Notes:  fmt.Sprintf("Pultosch: %s (%s)", pultosch.User.Name, pultosch.User.SchAcc),
			}
			spends = append(spends, &spend)
		}

		err = db.SaveMultipleSpend(spends)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
	}
}