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"
	adminarea "jannex/admin-dashboard-backend/routers/router/api/v1/adminArea"
	"jannex/admin-dashboard-backend/routers/router/api/v1/crm"
	"jannex/admin-dashboard-backend/routers/router/api/v1/customerfeedback"
	"jannex/admin-dashboard-backend/routers/router/api/v1/equipment"
	"jannex/admin-dashboard-backend/routers/router/api/v1/grouptasks"
	"jannex/admin-dashboard-backend/routers/router/api/v1/logmanagerserverconnections"
	"jannex/admin-dashboard-backend/routers/router/api/v1/machines"
	"jannex/admin-dashboard-backend/routers/router/api/v1/notification"
	"jannex/admin-dashboard-backend/routers/router/api/v1/productpipeline"
	"jannex/admin-dashboard-backend/routers/router/api/v1/user"
	"jannex/admin-dashboard-backend/routers/router/api/v1/users"
	"jannex/admin-dashboard-backend/routers/router/api/v1/webhook"
	"jannex/admin-dashboard-backend/socketclients"
	"time"

	"git.ex.umbach.dev/Alex/roese-utils/rslogger"
	"github.com/gofiber/fiber/v2"
	"gorm.io/gorm"
)

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

	v1.Post("/webhook", webhook.Webhook)

	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)
	u.Get("/profile", requestAccessValidation, user.GetUserProfile)
	u.Get("/", requestAccessValidation, user.UserInfo)

	us := v1.Group("/users")
	us.Get("/", requestAccessValidation, users.GetUsers)

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

	gs := v1.Group("/grouptasks")
	gs.Get("/:category", requestAccessValidation, grouptasks.GetGroupTasks)
	gs.Post("/start", requestAccessValidation, grouptasks.StartGroupTask)
	gs.Get(":category/steps/:groupTaskId", requestAccessValidation, grouptasks.GetGroupTaskSteps)

	e := v1.Group("/equipment")
	e.Get("/documentations/:stockItemId", requestAccessValidation, equipment.GetEquipmentDocumentations)
	e.Post("/documentation/create", requestAccessValidation, equipment.CreateEquipmentDocumentation)
	e.Get("/documentation/:stockItemId/:documentationId", requestAccessValidation, equipment.GetEquipmentDocumentation)
	e.Post("/documentation/edit", requestAccessValidation, equipment.EditEquipmentDocumentation)
	e.Get("/thumbnail/:stockItemId", equipment.GetEquipmentThumbnail)

	a := v1.Group("/adminarea")
	a.Get("/roles", requestAccessValidation, adminarea.GetRoles)

	ns := v1.Group("/notifications")
	ns.Get("/", requestAccessValidation, notification.GetNotifications)
	ns.Post("/", requestAccessValidation, notification.AddNotification)

	m := v1.Group("/machines")
	m.Post("/", requestAccessValidation, machines.GetMachines)

	l := v1.Group("/lmsc") // logmanagerserverconnections
	l.Get("/", requestAccessValidation, logmanagerserverconnections.GetConnectedLogManagerServers)

	c := v1.Group("/crm")
	// c.Get("/pipeline/:type/:dealPhase", requestAccessValidation, crm.GetCrmTypeCustomers)
	c.Post("/customer", requestAccessValidation, crm.GetCrmCustomer)
	c.Get("/customer/view/:id", requestAccessValidation, crm.GetCrmCustomerById)
	c.Post("/customer/update/:id", requestAccessValidation, crm.UpdateCrmCustomer)
	c.Post("/customer/create", requestAccessValidation, crm.CreateCrmCustomer)

	c.Get("/customers", requestAccessValidation, crm.GetAllCustomers)
	c.Post("/calls/create", requestAccessValidation, crm.CreateCrmCallProtocol)
	c.Delete("/calls/delete/:id", requestAccessValidation, crm.DeleteCrmCallProtocol)
	c.Post("/links", requestAccessValidation, crm.CreateCrmLink)
	c.Get("/links/:customerId", requestAccessValidation, crm.GetCrmLinks)
	c.Get("/link/:id", crm.CrmUseLink)
	c.Get("/link", crm.CrmNoLinkProvidedRedirect)
	c.Delete("/links/:id", requestAccessValidation, crm.DeleteCrmLink)

	cf := v1.Group("/customerfeedback")
	cf.Post("/", requestAccessValidation, customerfeedback.CreateCustomerFeedback)
	cf.Get("/origin/:origin", requestAccessValidation, customerfeedback.GetCustomerOriginFeedbacks)
	cf.Get("/origins", requestAccessValidation, customerfeedback.GetCustomerFeedbackOrigins)

	pp := v1.Group("/productpipeline")

	pp.Get("/", productpipeline.GetProducts)
	pp.Post("/vote", productpipeline.VoteProduct)

	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
	}

	// check if user has permission to use api keys
	if !socketclients.HasPermission(apiKey.UserId, utils.PermissionUserProfileApiKeys) {
		// delete api key from database
		database.DB.Delete(&apiKey)

		logger.AddSystemLog(rslogger.LogTypeInfo, "User %s has tried to use one of its api keys, but has no longer permission to do so",
			apiKey.UserId)

		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.SendMessageToUserWithTopic(apiKey.UserId,
		utils.SubscribedTopicUserProfile,
		"",
		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(rslogger.LogTypeInfo, "User %s has used one of its api keys", 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()
}
*/
