package user

import (
	"encoding/base64"
	"jannex/admin-dashboard-backend/modules/database"
	"jannex/admin-dashboard-backend/modules/logger"
	"jannex/admin-dashboard-backend/modules/structs"
	"jannex/admin-dashboard-backend/modules/utils"
	"jannex/admin-dashboard-backend/socketclients"

	"github.com/gofiber/fiber/v2"
	"github.com/rs/zerolog/log"
	"github.com/savsgio/gotils/uuid"
	"golang.org/x/crypto/bcrypt"
)

func UserLogin(c *fiber.Ctx) error {
	var body structs.UserLoginRequest

	if err := c.BodyParser(&body); err != nil {
		log.Error().Msg("Failed to parse body, err: " + err.Error())
		return c.Status(fiber.StatusBadRequest).JSON(err)
	}

	if err := utils.ValidateStruct(body); err != nil {
		log.Error().Msgf("Failed to validate body, err: %v", err)
		return c.SendStatus(fiber.StatusBadRequest)
	}

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

	if err != nil {
		log.Error().Msg("Failed to decode base64 password, err: " + err.Error())
		return c.Status(fiber.StatusBadRequest).JSON(err.Error())
	}

	if passwordValid := utils.IsPasswordLengthValid(string(decodedPassword)); !passwordValid {
		return c.SendStatus(fiber.StatusBadRequest)
	}

	var user structs.User

	database.DB.First(&user, "username = ?", body.Username)

	if user.Id == "" {
		log.Error().Msg("User not found")
		return c.SendStatus(fiber.StatusBadRequest)
	}

	if err := bcrypt.CompareHashAndPassword([]byte(user.Password), decodedPassword); err != nil {
		log.Error().Msg("Incorrect password")
		return c.SendStatus(fiber.StatusBadRequest)
	}

	if user.Deactivated {
		return c.SendStatus(fiber.StatusUnauthorized)
	}

	session, err := utils.GenerateSession()

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

	database.DB.Create(&structs.UserSession{
		Id:            session,
		IdForDeletion: uuid.V4(),
		UserId:        user.Id,
		UserAgent:     string(c.Context().UserAgent()),
		ExpiresAt:     utils.GetSessionExpiresAtTime()})

	logger.AddSystemLog(structs.LogMessage{
		Id:   19,
		Type: utils.LogTypeInfo,
		Messages: []structs.LogData{
			{
				Type:  "userId",
				Value: user.Id,
			},
		},
	})

	return c.JSON(structs.UserLoginResponse{Session: session})
}

func UserLogout(c *fiber.Ctx) error {
	session := utils.GetXAuhorizationHeader(c)

	database.DB.Delete(&structs.UserSession{}, "id = ?", session)

	socketclients.CloseAllUserSessionConnections(session)

	logger.AddSystemLog(structs.LogMessage{
		Id:   20,
		Type: utils.LogTypeInfo,
		Messages: []structs.LogData{
			{
				Type:  "userId",
				Value: c.Locals("userId").(string),
			},
		},
	})

	return c.SendStatus(fiber.StatusCreated)
}
