package router

import (
	"jannex/admin-dashboard-backend/modules/config"
	"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/routers/router/api/v1/equipment"
	"jannex/admin-dashboard-backend/routers/router/api/v1/grouptask"
	log "jannex/admin-dashboard-backend/routers/router/api/v1/logger"
	"jannex/admin-dashboard-backend/routers/router/api/v1/user"
	"jannex/admin-dashboard-backend/socketclients"
	"time"

	"github.com/gofiber/fiber/v2"
	"gorm.io/gorm"
)

func SetupRoutes(app *fiber.App) {
	v1 := app.Group("/v1")

	u := v1.Group("/user")
	u.Post("/auth/login", user.UserLogin)
	u.Delete("/auth/logout", requestAccessValidation, user.UserLogout)
	u.Delete("/session/:idForDeletion", requestAccessValidation, user.SignOutSession)
	u.Post("/avatar", requestAccessValidation, user.UpdateAvatar)

	//s := v1.Group("/scanner")
	//s.Post("/", jxscanner.AddScanner)
	//s.Post("/scan", scannerSessionValidation, jxscanner.ScanResult)
	//s.Delete("/", scannerSessionValidation, jxscanner.DeleteScanner)

	l := v1.Group("/log")
	l.Get("/", requestAccessValidation, log.GetSystemLog)

	g := v1.Group("/grouptasks")
	g.Post("/start", requestAccessValidation, grouptask.StartGroupTask)

	e := v1.Group("/equipment")
	// TODO: add user session validation
	//e.Get("/scanned/:stockItemId", requestAccessValidation, equipment.EquipmentScanned)
	//e.Get("/", requestAccessValidation, equipment.GetEquipment)
	e.Get("/documentation/:stockItemId", requestAccessValidation, equipment.GetEquipmentDocumentation)
	e.Post("/documentation/create", requestAccessValidation, equipment.CreateEquipmentDocumentation)
	// access validation here implented as it would require to implement authorization on web client side on Avatar Component
	e.Get("/thumbnail/media/part_images/:stockItemThumbnail", equipment.GetEquipmentThumbnail)

	app.Static("/", config.Cfg.FolderPaths.PublicStatic)
}

func requestAccessValidation(c *fiber.Ctx) error {
	// user session
	xAuthorization := utils.GetXAuhorizationHeader(c)

	if len(xAuthorization) == utils.LenHeaderXAuthorization {
		return userSessionValidation(c)
	}

	// api key
	xApiKey := utils.GetXApiKeyHeader(c)

	if len(xApiKey) == utils.LenHeaderXApiKey {
		return userApikeyTokenValidation(c)
	}

	return c.SendStatus(fiber.StatusUnauthorized)
}

func userApikeyTokenValidation(c *fiber.Ctx) error {
	xApikey := utils.GetXApiKeyHeader(c)

	if len(xApikey) != utils.LenHeaderXApiKey {
		return fiber.ErrUnauthorized
	}

	var apiKey structs.UserApiKey

	database.DB.Select("id, user_id, token, usage_count").First(&apiKey, "token = ?", xApikey)

	if apiKey.Token != xApikey {
		return fiber.ErrUnauthorized
	}

	lastUsed := time.Now()

	database.DB.Model(&structs.UserApiKey{}).Where("id = ?", apiKey.Id).Updates(map[string]interface{}{
		"usage_count": gorm.Expr("usage_count + ?", 1),
		"last_used":   lastUsed,
	})

	c.Locals("userId", apiKey.UserId)

	socketclients.SendMessageToUser(apiKey.UserId, "", structs.SendSocketMessage{
		Cmd: utils.SentCmdNewApiKeyUsageCount,
		Body: struct {
			Id         string
			UsageCount uint
			LastUsed   time.Time
		}{
			Id:         apiKey.Id,
			UsageCount: (apiKey.UsageCount + 1),
			LastUsed:   lastUsed,
		},
	})

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

	return c.Next()
}

func userSessionValidation(c *fiber.Ctx) error {
	xAuthorization := utils.GetXAuhorizationHeader(c)

	if len(xAuthorization) != utils.LenHeaderXAuthorization {
		return fiber.ErrUnauthorized
	}

	var userSession structs.UserSession

	database.DB.First(&userSession, "id = ?", xAuthorization)

	if userSession.Id != xAuthorization {
		return fiber.ErrUnauthorized
	}

	c.Locals("userId", userSession.UserId)

	return c.Next()
}

/*
func scannerSessionValidation(c *fiber.Ctx) error {
	xAuthorization := utils.GetXAuhorizationHeader(c)

	if len(xAuthorization) != utils.LenHeaderXAuthorization {
		return fiber.ErrUnauthorized
	}

	var scanner structs.Scanner

	database.DB.First(&scanner, "session = ?", xAuthorization)

	if scanner.Session != xAuthorization {
		return fiber.ErrUnauthorized
	}

	c.Locals("scannerId", scanner.Id)
	c.Locals("usedByUserId", scanner.UsedByUserId)

	return c.Next()
}
*/
