package main

import (
	"backend/login"
	"backend/models"
	secenes "backend/scenes"
	"backend/server"
	"backend/services"
	"backend/utils"
	"flag"
	"fmt"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"strings"
	"time"

	"gitea.tecamino.com/paadi/statusServer"
	"gitea.tecamino.com/paadi/tecamino-logger/logging"
	"github.com/gin-contrib/cors"
	"github.com/gin-gonic/gin"
)

func main() {

	var allowOrigins models.StringSlice

	flag.Var(&allowOrigins, "allowOrigin", "Allowed origin (can repeat this flag)")

	spa := flag.String("spa", "./dist/spa", "quasar spa files")
	cfgDir := flag.String("cfg", "./cfg", "config dir")
	servicesCfg := flag.String("services", "defaultConfigurations.json", "services config file name")
	workingDir := flag.String("workingDirectory", ".", "quasar spa files")
	ip := flag.String("ip", "0.0.0.0", "server listening ip")
	port := flag.Uint("port", 9500, "server listening port")
	debug := flag.Bool("debug", false, "log debug")
	flag.Parse()

	//change working directory only if value is given
	if *workingDir != "." && *workingDir != "" {
		os.Chdir(*workingDir)
	}

	wd, err := os.Getwd()
	if err != nil {
		log.Fatalf("Could not get working directory: %v", err)
	}

	folderName := filepath.Base(wd)
	logFileName := folderName + ".log"

	logger, err := logging.NewLogger(logFileName, &logging.Config{
		MaxSize:     1,
		MaxBackup:   3,
		MaxAge:      28,
		Debug:       *debug,
		TerminalOut: true,
	})
	if err != nil {
		logger.Error("main new logger", err.Error())
		panic(err)
	}

	//new login manager
	loginManager, err := login.NewLoginManager(".")
	if err != nil {
		logger.Error("main login manager", err.Error())
		panic(err)
	}

	//new scenes handler
	scenesHandler := secenes.NewScenesHandler("")

	//new scenes handler
	servicesHandler := services.NewServicesHandler(*cfgDir, *servicesCfg)

	// new server
	s := server.NewServer()

	// new status websocket
	statusWs, err := statusServer.NewStatusWebsocket(5, 256, logger)
	if err != nil {
		logger.Error("main", fmt.Sprintf("initialize status websocket: %s", err.Error()))
	}

	servicesHandler.LinkStatusServer(statusWs)
	//get local ip
	allowOrigins = append(allowOrigins, "http://localhost:9000", "http://localhost:9500")

	localIP, err := utils.GetLocalIP()
	if err != nil {
		logger.Error("main", fmt.Sprintf("get local ip: %s", err.Error()))
	} else {
		allowOrigins = append(allowOrigins, fmt.Sprintf("http://%s:9000", localIP), fmt.Sprintf("http://%s:9500", localIP))
	}

	s.Routes.Use(cors.New(cors.Config{
		AllowOrigins:     allowOrigins,
		AllowMethods:     []string{"POST", "GET", "DELETE", "OPTIONS"},
		AllowHeaders:     []string{"Origin", "Content-Type"},
		AllowCredentials: true,
	}))

	api := s.Routes.Group("/api")
	//set routes
	api.GET("/status", statusWs.NewConection)
	api.GET("/scenes/all", scenesHandler.LoadScenes)
	api.GET("/services/all", servicesHandler.GetAllAvaiableServices)
	api.GET("/services/load", servicesHandler.LoadAllServices)
	api.GET("/services/:service/start", servicesHandler.StartService)
	api.GET("/services/:service/stop", servicesHandler.StopService)
	api.POST("/login", loginManager.Login)
	api.POST("/user/add", loginManager.AddUser)
	api.POST("/scenes/save", scenesHandler.SaveScene)
	api.POST("/scenes/load", scenesHandler.LoadScene)
	api.POST("/services/add", servicesHandler.AddNewService)

	api.DELETE("/user",
		loginManager.RemoveUser)
	api.DELETE("/scenes", scenesHandler.DeleteScene)

	// Serve static files
	s.Routes.StaticFS("/assets", gin.Dir(filepath.Join(*spa, "assets"), true))
	s.Routes.NoRoute(func(c *gin.Context) {
		// Disallow fallback for /api paths
		if strings.HasPrefix(c.Request.URL.Path, "/api") {
			c.JSON(http.StatusNotFound, models.NewJsonErrorMessageResponse("API endpoint not found"))
			return
		}
		// Try to serve file from SPA directory
		filePath := filepath.Join(*spa, c.Request.URL.Path)
		if _, err := os.Stat(filePath); err == nil {
			c.File(filePath)
			return
		}
		// Fallback to index.html for SPA routing
		c.File(filepath.Join(*spa, "index.html"))

	})

	go func() {
		time.Sleep(500 * time.Millisecond)
		if err := utils.OpenBrowser(fmt.Sprintf("http://localhost:%d", *port), logger); err != nil {
			logger.Error("main", fmt.Sprintf("starting browser error : %s", err.Error()))
		}
	}()
	// start http server
	logger.Info("main", fmt.Sprintf("http listen on ip: %s port: %d", *ip, *port))
	if err := s.ServeHttp(*ip, *port); err != nil {
		logger.Error("main", "error http server "+err.Error())
	}
}
