package web

import (
	"context"

	"github.com/gofiber/fiber/v2"
	"github.com/gofiber/fiber/v2/middleware/cors"
	"github.com/gofiber/websocket/v2"
	"go.mongodb.org/mongo-driver/bson"
	serverConfig "krakatoa.net/backend/modules/configs/serverConfig"
	"krakatoa.net/backend/modules/logger"
	"krakatoa.net/backend/modules/mongo"
	"krakatoa.net/backend/modules/structs"
	"krakatoa.net/backend/routers/router"
)

func RunServer() {
	webApp := fiber.New(fiber.Config{AppName: "web"})

	webApp.Use(cors.New(cors.Config{
		AllowOrigins:     "https://dev.voice.krakatoa-roleplay.umbach.dev, https://voice.krakatoa-roleplay.umbach.dev, https://dev.mobile.krakatoa-roleplay.umbach.dev, https://mobile.krakatoa-roleplay.umbach.dev",
		AllowCredentials: true,
	}))

	router.SetupWebRoutes(webApp)

	webApp.Use("/ws", func(c *fiber.Ctx) error {
		token := c.Cookies("token")

		// check if the token is correct

		clientDb := structs.WebClientDb{}

		err := mongo.PlayersCollection.FindOne(context.TODO(), bson.D{{"$or", bson.A{bson.D{{"voiceSessionToken", token}}, bson.D{{"mobileSessionToken", token}}}}}).Decode(&clientDb)

		if err != nil || len(clientDb.VoiceSessionToken) == 0 && len(clientDb.MobileSessionToken) == 0 {
			logger.Mongo.Warnln("err", err)
			return c.SendStatus(fiber.StatusUnauthorized)
		}

		if websocket.IsWebSocketUpgrade(c) { // Returns true if the client requested upgrade to the WebSocket protocol
			return c.Next()
		}

		return c.SendStatus(fiber.StatusUpgradeRequired)
	})

	go RunHub()

	WebSocketServer(webApp)

	go webApp.Listen(serverConfig.Cfg.Servers.WebServer.Host)
}

func WebSocketServer(app *fiber.App) {
	app.Get("/ws", websocket.New(func(c *websocket.Conn) {
		defer func() {
			unregister <- c
			c.Close()
		}()

		register <- c

		for {
			messageType, msg, err := c.ReadMessage()

			logger.Web.Debugln("recv", msg)

			if err != nil {
				if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure) {
					logger.Web.Println("read error:", err)
				}

				return
			}

			if messageType == websocket.BinaryMessage {
				broadcast <- structs.SocketBroadcastData{Conn: c, Msg: msg}
			} else {
				logger.Web.Println("websocket message received of type", messageType)
			}
		}
	}))
}
