package http

import (
	"fmt"
	"log/slog"
	stdhttp "net/http"
	"os"
	"strings"
	"sync"

	"go.dev.pztrn.name/featurer/server/internal/application"
	"go.dev.pztrn.name/featurer/server/internal/services/core"

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

const (
	subsystem = "HTTP servers"
)

var _ = core.HTTP(&http{})

type http struct {
	app          *application.Application
	servers      map[string]*gin.Engine
	httpServers  map[string]*stdhttp.Server
	serversMutex sync.RWMutex
}

// Initialize initializes service.
func Initialize(app *application.Application) error {
	httpSrv := &http{
		app: app,
	}

	if err := app.RegisterService(httpSrv); err != nil {
		return fmt.Errorf("%w: register service: %w", core.ErrHTTP, err)
	}

	return nil
}

func (h *http) ConnectDependencies() error {
	return nil
}

func (h *http) GetName() string {
	return core.ServiceNameHTTP
}

func (h *http) Initialize() error {
	slog.Info("Initializing service...", "service", subsystem)

	h.servers = make(map[string]*gin.Engine)
	h.httpServers = make(map[string]*stdhttp.Server)

	serversNames := []string{core.ServerNameAPI, core.ServerNameCMS}

	for _, name := range serversNames {
		addr, found := os.LookupEnv("FEATURER_" + strings.ToUpper(name) + "_SERVER_ADDRESS")
		if !found {
			return fmt.Errorf("%w: getting address for server '%s' from env: not found", core.ErrHTTP, name)
		}

		h.createServer(name, addr)
	}

	return nil
}

func (h *http) LaunchStartupTasks() error {
	h.startServers()

	return nil
}

func (h *http) Shutdown() error {
	h.serversMutex.Lock()
	defer h.serversMutex.Unlock()

	for name, server := range h.httpServers {
		slog.Info("Stopping HTTP server...", "service", subsystem, "server", name)

		if err := server.Shutdown(h.app.GetContext()); err != nil {
			slog.Error("Failed to stop HTTP server!", "service", subsystem, "server", name, "error", err.Error())
		}
	}

	return nil
}
