package web_server

import (
	"context"
	"gardening/src/app/setup"
	"gardening/src/lib"
	"gardening/src/lib/config"
	"gardening/src/lib/dev_tool"
	erro "gardening/src/lib/error"
	"gardening/src/lib/logger"
	"net/http"
	"os"

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

type WebServer struct {
	GinRouter *setup.GinRouter
	Config    *config.Config
	DevTool   *dev_tool.DevTool
	Logger    *logger.Logger
	Data      struct {
		Router *gin.Engine
		Server *http.Server
		Port   string
	}
}

func (this *WebServer) Setup(ctx context.Context) {
	this.Data.Router = this.GinRouter.Setup(ctx)
	this.setupHttpServer(ctx)
}

func (this *WebServer) setupHttpServer(ctx context.Context) {
	this.determinePort()
	addr := "0.0.0.0:" + this.GetPort()
	this.Data.Server = &http.Server{
		Addr:    addr,
		Handler: this.Data.Router,
	}
}

func (this *WebServer) ListenAndServe(ctx context.Context) error {
	this.Logger.Info(ctx, "Starting web server on "+this.GetPort())
	if this.Config.IsDevEnv() {
		this.DevTool.RunDebugWsServer(ctx)
	}
	err := this.Data.Server.ListenAndServe()
	if err != nil {
		return erro.W("cannot run web router", err).KV("port", this.GetPort())
	}
	return nil
}

func (this *WebServer) determinePort() {
	if this.GetPort() != "" {
		return
	}
	port := os.Getenv("PORT")
	if port == "" {
		port = "8032"
	}
	this.SetPort(port)
}

func (this *WebServer) GetPort() string {
	return this.Data.Port
}

func (this *WebServer) SetPort(port string) {
	this.Data.Port = port
}

func (this *WebServer) HasServer() bool {
	return this.Data.Server != nil
}

func (this *WebServer) Shutdown(ctx context.Context) error {
	if this.Config.IsDevEnv() {
		err := this.DevTool.Shutdown(ctx)
		if err != nil {
			this.Logger.Warn(ctx, "Failed to shutdown dev tool server: "+err.Error())
		}
	}
	err := this.Data.Server.Shutdown(ctx)
	this.Logger.Info(ctx, "Webserver shutdown")
	return err
}

func (this *WebServer) MustShutdown(ctx context.Context) {
	err := this.Shutdown(ctx)
	lib.Poe(err)
}
