package routes

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"strings"

	"github.com/google/uuid"
	"github.com/jacobmveber-01839764/BudgetBuddy/db"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/primitive"
	"go.mongodb.org/mongo-driver/mongo/options"
	"go.mongodb.org/mongo-driver/mongo/readpref"
	"golang.org/x/crypto/bcrypt"
)

type LoginResponse struct {
	Status  int    `json:"status"`
	Name    string `json:"name"`
	Email   string `json:"email"`
	Session string `json:"session"`
}

func Login(w http.ResponseWriter, r *http.Request) {
	log.Println("* /auth/login")
	// prepare DB
	err := db.Client.Ping(context.Background(), readpref.Primary())
	if err != nil {
		db.Connect()
	}
	var userCollection = db.Client.Database("budgetbuddy").Collection("users")

	// var v contains POST credentials
	var v db.UserSchema
	r.ParseForm()
	v.Email = r.FormValue("email")
	v.Password = r.FormValue("password")
	if v.Email == "" || v.Password == "" {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintf(w, "{\"error\":\"both email and password must be provided\"}")
		return
	}

	// cmp struct will be compared with v to verify credentials
	var cmp db.UserSchema

	found := userCollection.FindOne(r.Context(), bson.D{primitive.E{Key: "email", Value: strings.ToLower(v.Email)}})
	if found.Err() != nil {
		w.WriteHeader(http.StatusUnauthorized)
		fmt.Fprintf(w, "{\"error\":\"account with that email does not exist\"}")
		return
	}
	err = found.Decode(&cmp)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	err = bcrypt.CompareHashAndPassword([]byte(cmp.Password), []byte(v.Password))
	if err != nil {
		w.WriteHeader(http.StatusUnauthorized)
		fmt.Fprintf(w, "{\"error\":\"invalid password\"}")
		return
	}

	// prepare ReturnedAccount struct to be sent back to the client
	var account LoginResponse
	err = found.Decode(&account)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	// set new session cookie for user, either persistent (remember me) or temporary
	sessionID := uuid.NewString()
	// var session = &http.Cookie{
	// 	Name:     "session",
	// 	Value:    sessionID,
	// 	Path:     "/",
	// 	Secure:   true,
	// 	SameSite: http.SameSiteLaxMode,
	// 	MaxAge:   0,
	// }
	// http.SetCookie(w, session)

	// update the new user session in the DB
	filter := bson.D{primitive.E{Key: "email", Value: strings.ToLower(account.Email)}}
	opts := options.Update().SetUpsert(true)
	update := bson.D{primitive.E{Key: "$set", Value: bson.D{primitive.E{Key: "session", Value: sessionID}}}}
	userCollection.UpdateOne(context.TODO(), filter, update, opts)

	account.Status = 200
	account.Session = sessionID
	acc, err := json.Marshal(account)
	if err != nil {
		fmt.Println("Error marshalling bson.D response")
	}
	fmt.Fprint(w, string(acc))
	// fmt.Println("logged in user successfully")
}
