package controllers

import (
	"api/database"
	"api/models"
	"api/utils"
	"os"
	"strconv"
	"time"

	"github.com/dgrijalva/jwt-go"
	"github.com/gofiber/fiber/v2"
	"golang.org/x/crypto/bcrypt"
)

func Hello(c *fiber.Ctx) error {
	return c.SendString("Hello!")
}

func Login(c *fiber.Ctx) error {
	var data map[string]string

	if err := c.BodyParser(&data); err != nil {
		return err
	}

	var user models.User

	database.DB.Where("email = ?", data["email"]).First(&user)

	if user.Id == 0 {
		c.Status(fiber.StatusNotFound)
		return c.JSON(fiber.Map{
			"message": "User not found",
		})
	}

	if err := bcrypt.CompareHashAndPassword(user.Password, []byte(data["password"])); err != nil {
		c.Status(fiber.StatusBadRequest)
		return c.JSON(fiber.Map{
			"message": "Incorrect password",
		})
	}

	type customClaims struct {
		Userid string `json:"user"`
		jwt.StandardClaims
	}

	tok := customClaims{
		Userid: strconv.Itoa(int(user.Id)),
		StandardClaims: jwt.StandardClaims{
			Issuer:    strconv.Itoa(int(user.Id)),
			ExpiresAt: time.Now().Add(time.Hour * 1).Unix(),
		},
	}

	claims := jwt.NewWithClaims(jwt.SigningMethodHS256, tok)

	token, err := claims.SignedString([]byte(os.Getenv("API_SECRET")))
	if err != nil {
		c.Status(fiber.StatusInternalServerError)
		return c.JSON(fiber.Map{
			"message": "Could't login",
		})
	}

	cookie := fiber.Cookie{
		Name:     "jwt",
		Value:    token,
		Expires:  time.Now().Add(time.Hour * 1),
		HTTPOnly: true,
	}

	c.Cookie(&cookie)

	return c.JSON(token)
}

func Logout(c *fiber.Ctx) error {
	cookie := fiber.Cookie{
		Name:     "jwt",
		Value:    "",
		Expires:  time.Now().Add(-time.Hour),
		HTTPOnly: true,
	}

	c.Cookie(&cookie)

	return c.JSON(fiber.Map{
		"message": "Successful logout",
	})
}

func AddUser(c *fiber.Ctx) error {
	var data map[string]string

	if err := c.BodyParser(&data); err != nil {
		return err
	}

	passwd, _ := utils.HashPassword(data["password"])

	user := models.User{
		Name:      data["name"],
		Email:     data["email"],
		Password:  passwd,
		UserType:  data["usertype"],
		Blocked:   "N",
		First:     "S",
		Cancelled: "N",
		CreatedBy: data["creator"],
	}

	database.DB.Create(&user)

	if user.Id == 0 {
		return c.SendStatus(fiber.StatusFound)
	}

	c.SendStatus(fiber.StatusCreated)
	return c.JSON(user)
}

func User(c *fiber.Ctx) error {
	cookie := c.Cookies("jwt")

	var user models.User

	claims, err := utils.VerifyAuthentication(c, cookie)
	if err != nil {
		c.Status(fiber.StatusUnauthorized)
		return c.JSON(fiber.Map{
			"message": "Unauthenticated",
		})
	}

	database.DB.Where("id = ?", claims.Issuer).First(&user)

	if user.Id == 0 {
		c.Status(fiber.StatusUnauthorized)
		return c.JSON(fiber.Map{
			"message": "Unauthenticated",
		})
	}

	return c.JSON(user)
}

func Users(c *fiber.Ctx) error {
	cookie := c.Cookies("jwt")

	var user []models.User

	_, err := utils.VerifyAuthentication(c, cookie)
	if err != nil {
		c.Status(fiber.StatusUnauthorized)
		return c.JSON(fiber.Map{
			"message": "Unauthenticated",
		})
	}

	database.DB.Find(&user)

	if len(user) == 0 {
		c.Status(fiber.StatusUnauthorized)
		return c.JSON(fiber.Map{
			"message": "Unauthenticated",
		})
	}

	return c.JSON(user)
}
