package main

import (
	"fmt"
	"os"
	"time"
    "os/signal"
	"log"
    "net/http"
	"context"

	"github.com/getkin/kin-openapi/openapi3"
	"github.com/deepmap/oapi-codegen/pkg/middleware"
	"github.com/labstack/echo/v4"
	echomiddleware "github.com/labstack/echo/v4/middleware"

	"sku61.com/InvestAccnt/api"
	"sku61.com/InvestAccnt/api/gen"
	"sku61.com/InvestAccnt/api/errorh"

)


func Run(e *echo.Echo, addressPort string, timeOut time.Duration, msgLevel int)  {

	var runChan = make(chan os.Signal, 1)

    // Set up a context to allow for graceful server shutdowns in the event
    // of an OS interrupt (defers the cancel just in case)
    ctx, cancel := context.WithTimeout(
        context.Background(),
        timeOut,
    )
    defer cancel()

    // Handle ctrl+c/ctrl+x interrupt
    signal.Notify(runChan, os.Interrupt)

	if (msgLevel > 0) {
    	log.Printf("Server is starting on %s\n", addressPort)
	}

    go func() {
        if err := e.Start(addressPort); err != nil {
            if err == http.ErrServerClosed {
                // Normal interrupt operation, ignore
            } else {
                log.Fatalf("Server failed to start due to err: %v", err)
            }
        }
    }()

    interrupt := <-runChan

	if (msgLevel > 0) {
    	log.Printf("Server is shutting down due to %+v\n", interrupt)
	}
    if err := e.Server.Shutdown(ctx); err != nil {
		if ("interrupt" != fmt.Sprintf("%v", interrupt)) {
        	log.Printf("Server was unable to gracefully shutdown due to err: '%+v'", err)
		}
    }

}


func main() {

	configPath := "../config/InvestAccnt.yaml"
	softwareConfig, err := api.ParseFlags(configPath)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error loading configuration,flags\n")
		fmt.Fprintf(os.Stderr, "Error detail: %v\n", err)
		os.Exit(1)
	}
	if (softwareConfig.Support.Level > 2) {
		log.Printf("Message verbosity level: %d", softwareConfig.Support.Level)
	}

	swagger, err := gen.GetSwagger()
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error loading Open API spec\n: %s", err)
		os.Exit(1)
	}

	// Create an instance of our handler which satisfies the generated interface
	var microService, _  = api.NewMicroService(*softwareConfig)

	// Adjust servers to fit configuration
	swagger.Servers = nil
	server := openapi3.Server{
		URL: microService.Configuration.Server.BasePath,
	}
	swagger.AddServer(&server) 

	e := echo.New()

	// Log all requests
	e.Use(echomiddleware.Logger())
	// Custom error handling
	e.HTTPErrorHandler = errorh.NewHttpErrorHandler().Handler

	var options middleware.Options
	if (!microService.IsProductionEnvironment()) {
		options.Skipper = func(c echo.Context) bool {
				return microService.BrowseSkipper(c.Request().URL.Path)
		}
	}
	options.Options.AuthenticationFunc = microService.Authn.AuthnFunc 

	// Use our validation middleware to check all requests against the
	// OpenAPI schema.
	e.Use(middleware.OapiRequestValidatorWithOptions(swagger, &options))
	e.Use(echomiddleware.GzipWithConfig(echomiddleware.GzipConfig{
		Level: 3,
	}))

	microService.RegisterHandlers(e)
	
	if (microService.Configuration.Support.Level < 1) {
		e.HideBanner = true
	}

	e.Server.ReadTimeout =  microService.Configuration.Server.Timeout.Read * time.Second
	e.Server.WriteTimeout = microService.Configuration.Server.Timeout.Write * time.Second
	e.Server.IdleTimeout =  microService.Configuration.Server.Timeout.Idle * time.Second

	addressPort := fmt.Sprintf("%s:%d", microService.Configuration.Server.Host, microService.Configuration.Server.Port)
	timeOut := microService.Configuration.Server.Timeout.Server * time.Second
	// And we serve HTTP until the world ends.
	Run(e, addressPort, timeOut, microService.Configuration.Support.Level)
}

