package main

import (
	"fmt"
	"os"
	_ "ttime/docs"
	"ttime/internal/config"
	"ttime/internal/database"
	"ttime/internal/handlers"

	"github.com/BurntSushi/toml"
	"github.com/gofiber/fiber/v2"
	"github.com/gofiber/fiber/v2/middleware/logger"
	"github.com/gofiber/swagger"

	jwtware "github.com/gofiber/contrib/jwt"
)

//	@title			TTime API
//	@version		0.0.1
//	@description	This is the API for TTime, a time tracking application.

//	@license.name	AGPL
//	@license.url	https://www.gnu.org/licenses/agpl-3.0.html

//@securityDefinitions.apikey bererToken
//@in header
//@name Authorization

//	@host		localhost:8080
//	@BasePath	/api

// @externalDocs.description	OpenAPI
// @externalDocs.url			https://swagger.io/resources/open-api/

func main() {
	conf, err := config.ReadConfigFromFile("config.toml")
	if err != nil {
		conf = config.NewConfig()
		_ = conf.WriteConfigToFile("config.toml")
	}

	// Pretty print the current config with toml
	_ = toml.NewEncoder(os.Stdout).Encode(conf)

	fmt.Printf("Starting server on http://localhost:%d\n", conf.Port)
	fmt.Printf("For documentation, go to http://localhost:%d/swagger/index.html\n", conf.Port)

	// Connect to the database
	db := database.DbConnect(conf.DbPath)
	// Migrate the database
	if err = db.Migrate(); err != nil {
		fmt.Println("Error migrating database: ", err)
		os.Exit(1)
	}

	if err = db.MigrateSampleData(); err != nil {
		fmt.Println("Error migrating sample data: ", err)
		os.Exit(1)
	}

	// Get our global state
	gs := handlers.NewGlobalState(db)
	// Create the server
	server := fiber.New()

	server.Use(logger.New())

	// Mounts the swagger documentation, this is available at /swagger/index.html
	server.Get("/swagger/*", swagger.HandlerDefault)

	// Mount our static files (Beware of the security implications of this!)
	// This will likely be replaced by an embedded filesystem in the future
	server.Static("/", "./static")

	// Register our unprotected routes
	server.Post("/api/register", gs.Register)
	server.Post("/api/login", gs.Login)

	// Every route from here on will require a valid JWT
	server.Use(jwtware.New(jwtware.Config{
		SigningKey: jwtware.SigningKey{Key: []byte("secret")},
	}))

	// Protected routes (require a valid JWT bearer token authentication header)
	server.Post("/api/submitWeeklyReport", gs.SubmitWeeklyReport)
	server.Get("/api/getUserProjects", gs.GetUserProjects)
	server.Post("/api/loginrenew", gs.LoginRenew)
	server.Delete("/api/userdelete/:username", gs.UserDelete) // Perhaps just use POST to avoid headaches
	server.Delete("api/project/:projectID", gs.DeleteProject) // WIP
	server.Post("/api/project", gs.CreateProject)             // WIP
	server.Get("/api/project/:projectId", gs.GetProject)
	server.Get("/api/project/getAllUsers", gs.GetAllUsersProject)
	server.Get("/api/getWeeklyReport", gs.GetWeeklyReport)
	server.Post("/api/signReport", gs.SignReport)
	server.Put("/api/addUserToProject", gs.AddUserToProjectHandler)
	server.Put("/api/changeUserName", gs.ChangeUserName)
	server.Post("/api/promoteToAdmin", gs.PromoteToAdmin)
	server.Get("/api/users/all", gs.ListAllUsers)
	server.Get("/api/getWeeklyReportsUser/:projectName", gs.GetWeeklyReportsUserHandler)
	server.Get("/api/checkIfProjectManager/:projectName", gs.IsProjectManagerHandler)
	server.Post("/api/ProjectRoleChange", gs.ProjectRoleChange)
	server.Get("/api/getUsersProject/:projectName", gs.ListAllUsersProject)

	// Announce the port we are listening on and start the server
	err = server.Listen(fmt.Sprintf(":%d", conf.Port))
	if err != nil {
		fmt.Println("Error starting server: ", err)
	}
}
