package main

import (
	"embed"
	_ "embed"
	"fmt"
	"io/fs"
	"log"
	"net/http"
	"os"

	"github.com/asdine/storm/v3"
	"github.com/gofiber/fiber/v2"
	"github.com/gofiber/fiber/v2/middleware/basicauth"
	"github.com/gofiber/fiber/v2/middleware/cors"
	"github.com/gofiber/fiber/v2/middleware/filesystem"
	"github.com/gofiber/fiber/v2/middleware/logger"
	"github.com/rs/zerolog"
)

var (
	//go:embed frontend/build
	frontend embed.FS
)

type Server struct {
	Config    *Config
	Database  *storm.DB
	WebServer *fiber.App
	LogFile   *os.File
	Log       zerolog.Logger
}

func main() {

	server := Server{}
	err := LoadConfig(&server)
	if err != nil {
		log.Fatal("Unable to setup config and logging: ", err)
	}
	fmt.Println("Server: ", server.Config)
	app := fiber.New()
	// Setup CORS
	app.Use(cors.New(cors.Config{
		AllowOrigins: "http://localhost:3000, http://localhost",
		AllowHeaders: "Origin, Content-Type, Accept",
	}))
	// Setup our logger
	app.Use(logger.New(logger.Config{
		Output:   server.LogFile,
		TimeZone: server.Config.Timezone,
		Format:   `{"logtype":"webserver", "pid":"${pid}", "requestid":"${locals:requestid}", "status":"${status}", "method":"${method}", "path":"${path}​"}​` + "\n",
	}))

	server.WebServer = app
	defer server.LogFile.Close()             // Close out our logfile when closing server.
	server.Database = SetupDatabase(&server) // Setup our database
	defer server.Database.Close()

	server.Log.Info().Msg("Database and Config loaded, starting webserver...") // Send all good message

	// Loading in the frontend files that were embedded
	reactFE, err := fs.Sub(frontend, "frontend/build")
	if err != nil {
		server.Log.Fatal().Msgf("Unable to load frontend/build: ", err)
	}
	staticFE, err := fs.Sub(frontend, "frontend/build/static")
	if err != nil {
		server.Log.Fatal().Msgf("Unable to load static files: ", err)
	}
	// serve our frontend and static files from our embed
	server.WebServer.Use("/", filesystem.New(filesystem.Config{
		Root: http.FS(reactFE),
	}))
	server.WebServer.Use("/static", filesystem.New(filesystem.Config{
		Root:       http.FS(staticFE),
		PathPrefix: "static",
	}))

	// Load in our routes
	server.WebServer.Get("/hello", func(c *fiber.Ctx) error { // Basic Hello Route
		return c.SendString("GoInventorize Backend Hello Route!")
	})
	// Location Routes
	server.WebServer.Get("/config", server.GetServerConfig)
	// Setup our basic authentication if defined
	if server.Config.Authentication.BasicAuth {
		app.Use(basicauth.New(basicauth.Config{
			Users: map[string]string{
				server.Config.Authentication.UserName: server.Config.Authentication.Password,
			},
		}))
	}

	server.WebServer.Get("/locations", server.GetAllLocationsHandler)
	server.WebServer.Post("/locations/new", server.AddNewLocationHandler)
	server.WebServer.Delete("/locations/:locID", server.DeleteLocationHandler)
	fmt.Println("Everything ready, starting server! ", fmt.Sprintf(":%s", server.Config.Server.Port))
	server.WebServer.Listen(fmt.Sprintf(":%s", server.Config.Server.Port))
}
