package cmd

import (
	"flag"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"

	"git.espin.casa/albert/cml04-falcon-printer/routes"
	"git.espin.casa/albert/cml04-falcon-printer/storage"
	"git.espin.casa/albert/logger"
	"github.com/julienschmidt/httprouter"
)

func Run() error {
	logLevel := flag.String("log-level", "debug", "trace log level")
	httpAddr := flag.String("http-addr", ":3000", "http bind address")
	dbUsername := flag.String("db-username", "postgres", "database username")
	dbPassword := flag.String("db-password", "Me8140@01", "database user password")
	dbHost := flag.String("db-host", "10.1.152.13", "database host address")
	dbPort := flag.Int("db-port", 5432, "database tcp port")
	dbName := flag.String("db-name", "falcon", "database user password")
	flag.Parse()
	// setup logger
	log := logger.New(os.Stdout, *logLevel)
	// log fields
	logFields := logger.LogFields{
		"http-bind": *httpAddr,
		"log_level": *logLevel,
	}
	// create storage
	storage, err := storage.New(&storage.DBConfig{
		Username: *dbUsername,
		Password: *dbPassword,
		Host:     *dbHost,
		Port:     *dbPort,
		Name:     *dbName,
	})
	// handle error
	if err != nil {
		log.Error("create storage failed", err, logFields)
		return err
	}
	// create router
	router := httprouter.New()
	// create routes
	routes.CreateRoutes(router, storage)
	// serve static files
	router.ServeFiles("/assets/*filepath", http.Dir("assets"))
	// create http server
	server := http.Server{
		Addr:         *httpAddr,
		ReadTimeout:  5 * time.Second,
		WriteTimeout: 5 * time.Second,
		IdleTimeout:  5 * time.Second,
		Handler:      router,
	}
	// start the http server
	go func() {
		if err := server.ListenAndServe(); err != nil {
			panic(err)
		}
	}()
	// info banner
	log.Info("started Falcon Printer", logFields)
	// wait signal to finish
	signal := WaitSignal()
	log.Info("signal received", logFields.Add(logger.LogFields.Add(logFields, logger.LogFields{
		"signal": signal,
	})))
	return nil
}

// WaitSignal catching exit signal
func WaitSignal() os.Signal {
	ch := make(chan os.Signal, 2)
	signal.Notify(
		ch,
		syscall.SIGINT,
		syscall.SIGQUIT,
		syscall.SIGTERM,
	)
	for {
		sig := <-ch
		switch sig {
		case syscall.SIGINT, syscall.SIGQUIT, syscall.SIGTERM:
			return sig
		}
	}
}
