// Package classification JNX Log Manager API Documentation.
//
// Schemes: https
// Host: jannex
// BasePath: /v1
// Version: 1.0.0
//
// Consumes:
// - application/json
//
// Produces:
// - application/json
//
// swagger:meta
package main

import (
	"bufio"
	"fmt"
	"jannex/log-manager/modules/cache"
	"jannex/log-manager/modules/config"
	"jannex/log-manager/modules/structs"
	"jannex/log-manager/modules/utils"
	"jannex/log-manager/routers/router"

	"github.com/gofiber/fiber/v2"
	"github.com/gofiber/fiber/v2/middleware/cors"
	"github.com/gofiber/fiber/v2/middleware/logger"
	futils "github.com/gofiber/fiber/v2/utils"
	"github.com/google/uuid"
	"github.com/valyala/fasthttp"
)

func init() {
	config.LoadConfig()
	utils.ValidatorInit()

	utils.CreateDirectoryIfNotExists(config.Cfg.LogFolder)
}

func main() {
	app := fiber.New(fiber.Config{
		BodyLimit: 100 * 1024 * 1024,
	})

	app.Use(cors.New(cors.Config{}))

	app.Use(logger.New(logger.Config{
		Format: "${pid} ${locals:requestid} ${status} - ${latency} ${method} ${path}​\n",
	}))

	router.SetupRoutes(app)

	if config.Cfg.SSEServerEnabled {
		app.Get("/v1/log/sse/:logType/:date", func(c *fiber.Ctx) error {
			fmt.Println("GET /:logType/:date", c.Params("logType"), c.Params("date"))

			logType := futils.CopyString(c.Params("logType"))
			date := futils.CopyString(c.Params("date"))

			c.Set("Content-Type", "text/event-stream")
			c.Set("Cache-Control", "no-cache")
			c.Set("Connection", "keep-alive")
			c.Set("Transfer-Encoding", "chunked")

			c.Context().SetBodyStreamWriter(fasthttp.StreamWriter(func(w *bufio.Writer) {
				var sseclient structs.SSEClient

				sseclient.MessageChannel = make(chan structs.SSEClientChannelMessage)
				sseclient.LogType = logType
				sseclient.Date = date

				clientId := uuid.New()

				cache.SSEClients[clientId] = sseclient

				fmt.Printf("NEW CLIENT %v", sseclient)
				fmt.Printf("%d CLIENTS CONNECTED", len(cache.SSEClients))

				for message := range sseclient.MessageChannel {
					fmt.Fprintf(w, "data: %s\n\n", message.Message)

					err := w.Flush()

					if err != nil {
						// Refreshing page in web browser will establish a new
						// SSE connection, but only (the last) one is alive, so
						// dead connections must be closed here.

						for id, sseClient := range cache.SSEClients {
							if id == message.ClientId {
								close(sseClient.MessageChannel)
								delete(cache.SSEClients, id)
								fmt.Printf("DELETE clientId: %s", id)
							}
						}
					}
				}
			}))

			return nil
		})
	}

	app.Listen(config.Cfg.Host + ":" + config.Cfg.Port)
}
