package service

import (
        "context"
        "crypto/tls"
        "fmt"
        "net/http"
        "path/filepath"
        "time"
        "strings"

        "engine/internal/handler"
        "engine/internal/logger"
        "engine/pkg/auxtool/aux509"
        "engine/pkg/auxtool/auxhttp"

        "github.com/gin-gonic/gin"
)

const (
        httpTimeout = 360
)

type ServiceConfig struct {
        Handler *handler.Handler
        PortNum int
        WebDir  string
}

type Service struct {
        hand   *handler.Handler
        hsrv   *http.Server
        log    *logger.Logger
        engine *gin.Engine

        portnum int
        webdir  string
}

func NewService(conf *ServiceConfig) (*Service, error) {
        var err error
        svc := &Service{
                hand:    conf.Handler,
                portnum: conf.PortNum,
                webdir:  conf.WebDir,
        }
        svc.log = logger.NewLogger("service")
        return svc, err
}

func (svc *Service) Build() error {
        var err error
        svc.log.Debugf("Build service")

        gin.SetMode(gin.ReleaseMode)
        gin.DisableConsoleColor()

        svc.engine = gin.New()
        svc.engine.Use(gin.Recovery())
        svc.engine.Use(CorsMiddleware())
        svc.engine.Use(LogMiddleware())

        rootPath := filepath.Join(svc.webdir)
        cssPath := filepath.Join(rootPath, "css")
        fontsPath := filepath.Join(rootPath, "fonts")
        jsPath := filepath.Join(rootPath, "js")
        indexPath := filepath.Join(rootPath, "index.html")

        svc.engine.Use(Serve("/", LocalFile(rootPath, false)))
        svc.engine.Static("/css", cssPath)
        svc.engine.Static("/fonts", fontsPath)
        svc.engine.Static("/js", jsPath)

        apiGroup := svc.engine.Group("api")
        v1Group := apiGroup.Group("v1")
        {
                sessionGroup := v1Group.Group("session")
                sessionGroup.POST("create", svc.hand.CreateSession)

                healthGroup := v1Group.Group("health")
                healthGroup.POST("get", svc.hand.GetHealth)

        }
        svc.engine.StaticFile("/", indexPath)

        noRouteFunc := func(gctx *gin.Context) {
                contentType := gctx.GetHeader("Content-Type")
                contentType = strings.ToLower(contentType)
                if strings.Contains(contentType, "application/json") {
                        err := fmt.Errorf("No route")
                        auxhttp.SendError(gctx, err)

                } else {
                    gctx.Redirect(301, "/")
                }
        }
        svc.engine.NoRoute(noRouteFunc)

        cert, err := aux509.GetTLSCert("WEB", "ENGINE")
        if err != nil {
                return err
        }
        tlsConfig := tls.Config{
                Certificates: []tls.Certificate{cert},
                ClientAuth:   tls.NoClientCert,
                InsecureSkipVerify: true,
        }
        listenAddr := fmt.Sprintf(":%d", svc.portnum)
        svc.hsrv = &http.Server{
                Addr:      listenAddr,
                Handler:   svc.engine,
                TLSConfig: &tlsConfig,
        }
        return err
}



func (svc *Service) Run() error {
        var err error
        for _, route := range svc.engine.Routes() {
                svc.log.Debugf("The route is registered: %s %s", route.Method, route.Path)
        }
        svc.log.Infof("Service listening at %d port", svc.portnum)
        err = svc.hsrv.ListenAndServeTLS("", "")
        if err != nil {
                return err
        }
        return err
}

func (svc *Service) Stop() {
        svc.log.Infof("Stopping service")
        if svc.hsrv != nil {
                downWaiting := 5 * time.Second
                ctx, _ := context.WithTimeout(context.Background(), downWaiting)
                svc.hsrv.Shutdown(ctx)
        }
}
