package user

import (
	"strings"

	"git.ex.umbach.dev/LMS/libcore/models"
	"github.com/gofiber/fiber/v2"
	"github.com/google/uuid"
	"lms.de/backend/modules/database"
	"lms.de/backend/modules/structs"
	"lms.de/backend/modules/utils"
	"lms.de/backend/socketclients"
)

func GetUserProfile(c *fiber.Ctx) error {
	// swagger:operation GET /user/profile user getUserProfile
	// ---
	// summary: Get user profile
	// consumes:
	// - application/json
	// produces:
	// - application/json
	// responses:
	//   '200':
	//     description: User profile fetched successfully
	//     schema:
	//       "$ref": "#/definitions/GetUserProfileResponse"
	//   '400':
	//     description: Invalid request body
	//   '500':
	//     description: Failed to fetch account

	var user structs.GetUserProfileResponse

	database.DB.Model(&models.User{}).
		Select("email", "first_name", "last_name", "profile_picture_url", "role_id").
		Where("id = ?", c.Locals("userId").(string)).
		First(&user)

	return c.JSON(user)
}

func UpdateUserProfilePicture(c *fiber.Ctx) error {
	// swagger:operation POST /user/profile/picture user updateUserProfilePicture
	// ---
	// summary: Update user profile picture
	// consumes:
	// - application/json
	// produces:
	// - application/json
	// parameters:
	// - name: file
	//   in: formData
	//   type: file
	//   required: true
	// responses:
	//   '200':
	//     description: Profile picture updated successfully
	//     schema:
	//       type: string
	//   '400':
	//     description: Invalid request body
	//   '500':
	//     description: Failed to update profile picture

	fileHeader, err := c.FormFile("file")

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

	if fileHeader.Size > utils.MaxImageSize {
		return c.SendStatus(fiber.StatusBadRequest)
	}

	if !utils.IsFileTypeAllowed(fileHeader.Header.Get("Content-Type"), utils.AcceptedImageFileTypes) {
		return c.SendStatus(fiber.StatusBadRequest)
	}

	// get current profile picture

	user := models.User{}

	if err := database.DB.Model(&models.User{}).
		Select("profile_picture_url").
		Where("id = ?", c.Locals("userId").(string)).
		First(&user).Error; err != nil {
		return c.SendStatus(fiber.StatusInternalServerError)
	}

	// delete current profile picture

	if user.ProfilePictureUrl != "" {
		utils.DeleteFile(user.ProfilePictureUrl)
	}

	fileName := uuid.New().String() + "." + strings.Split(fileHeader.Header["Content-Type"][0], "/")[1]

	databasePath, publicPath := utils.GetFullImagePathForUserProfilePicture(c.Locals("organizationId").(string))

	utils.CreateFolderStructureIfNotExists(publicPath)

	profilePictureUrl := databasePath + fileName

	if err := database.DB.Model(&models.User{}).
		Where("id = ?", c.Locals("userId").(string)).
		Update("profile_picture_url", profilePictureUrl).Error; err != nil {
		return c.SendStatus(fiber.StatusInternalServerError)
	}

	if err := c.SaveFile(fileHeader, publicPath+fileName); err != nil {
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
			"error": "Failed to save file",
		})
	}

	socketclients.SendMessageToUserWithTopicExceptBrowserTabSession(
		c.Locals("userId").(string),
		utils.SubscribedTopicUserProfile,
		c.Locals("browserTabSession").(string),
		structs.SendSocketMessage{
			Cmd:  utils.SendCmdUserProfilePictureUpdated,
			Body: profilePictureUrl,
		},
	)

	return c.JSON(fiber.Map{
		"Data": databasePath + fileName,
	})
}

func GetUser(c *fiber.Ctx) error {
	// swagger:operation GET /user/{userId} user getUser
	// ---
	// summary: Get user
	// consumes:
	// - application/json
	// produces:
	// - application/json
	// parameters:
	// - name: userId
	//   in: path
	//   type: string
	//   required: true
	// responses:
	//   '200':
	//     description: User fetched successfully
	//     schema:
	//       "$ref": "#/definitions/GetUserResponse"
	//   '400':
	//     description: Invalid request body
	//  '404':
	//     description: User not found
	//   '500':
	//     description: Failed to fetch user

	var params structs.UserIdParam

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

	var user structs.GetUserResponse

	if err := database.DB.Model(&models.User{}).
		Select("id", "first_name", "last_name", "profile_picture_url").
		Where("id = ? AND organization_id = ?", params.UserId, c.Locals("organizationId").(string)).
		First(&user).Error; err != nil {
		return c.SendStatus(fiber.StatusNotFound)
	}

	return c.JSON(user)
}
