package user

import (
	"encoding/base64"

	"git.umbach.dev/app-idea/rest-api/modules/database"
	"git.umbach.dev/app-idea/rest-api/modules/structs"
	"github.com/gofiber/fiber/v2"
	log "github.com/sirupsen/logrus"
	"golang.org/x/crypto/bcrypt"
)

type LoginInput struct {
	Username string `json:"username"`
	Email    string `json:"email"`
	Password string `json:"password"`
}

func Login(c *fiber.Ctx) error {
	// swagger:operation POST /user/login User userLogin
	// ---
	// summary: Login a user
	// produces:
	// - application/json
	// parameters:
	// - name: username or email
	//   in: query
	//   description: username or email
	//   type: string
	//   required: true
	// - name: password
	//   in: query
	//   description: password (base64) of the user
	//   type: string
	//   required: true
	// responses:
	//   '200':
	//     description: login success
	//   '401':
	//     description: login credentials not correct

	var input LoginInput

	if err := c.BodyParser(&input); err != nil {
		return c.SendStatus(fiber.StatusBadRequest)
	}

	log.Println(input)

	if input.Username != "" && /*!isValid(input.Username, 3, 30) */ !isUsernameValid(input.Username) || input.Email != "" && !isEmailValid(input.Email) || input.Username == "" && input.Email == "" || input.Password == "" {
		log.Info("bad")
		return c.SendStatus(fiber.StatusBadRequest)
	}

	decodedPassword, err := base64.StdEncoding.DecodeString(input.Password)

	if err != nil {
		log.Debugln("base64 decoding failed:", err)
		return c.SendStatus(fiber.StatusBadRequest)
	}

	input.Password = string(decodedPassword)

	db := database.DB
	user := structs.User{Name: input.Username, Email: input.Email}

	if input.Username != "" {
		db.Select("id, hashtag, password").Where("name = ?", input.Username).Find(&user)
	} else {
		db.Select("id, hashtag, name, password").Where("email = ?", input.Email).Find(&user)
	}

	if user.Name == "" && user.Email == "" {
		log.Info("test1", user)
		return c.SendStatus(fiber.StatusUnauthorized)
	}

	err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(input.Password))

	if err != nil {
		log.Warnln("Failed to comapare bcrypt password", err)
		return c.SendStatus(fiber.StatusUnauthorized)
	}

	sessionId, err := createUserSession(database.DB, user.Id, c.IP(), string(c.Context().UserAgent()))

	if err != nil {
		return c.SendStatus(fiber.StatusInternalServerError)
	}

	expires := getUserSessionExpiresTime()

	cfg := cfg.Settings.Cookies

	c.Cookie(&fiber.Cookie{Name: cfg.SessionId, Value: sessionId, Secure: true, HTTPOnly: true, Expires: expires})
	if user.Name != "" {
		c.Cookie(&fiber.Cookie{Name: cfg.Username, Value: user.Name, Secure: true, Expires: expires})
	}
	c.Cookie(&fiber.Cookie{Name: cfg.UserHashtag, Value: user.Hashtag, Secure: true, Expires: expires})

	return c.SendStatus(fiber.StatusCreated)
}
