// Package server initializes and runs the application server.
// It sets up configurations, initializes the database, services, and controllers,
// loads HTML templates, and starts the HTTP server.
package server

import (
	"context"
	"net/http"
	"path/filepath"
	"time"

	"GoMembership/internal/config"
	"GoMembership/internal/controllers"
	"GoMembership/internal/middlewares"
	"GoMembership/internal/repositories"
	"GoMembership/internal/validation"

	"GoMembership/internal/routes"
	"GoMembership/internal/services"
	"GoMembership/pkg/logger"

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

var shutdownChannel = make(chan struct{})
var srv *http.Server

// Run initializes the server configuration, sets up services and controllers, and starts the HTTP server.
func Run() {

	emailService := services.NewEmailService(config.SMTP.Host, config.SMTP.Port, config.SMTP.User, config.SMTP.Password)
	var consentRepo repositories.ConsentRepositoryInterface = &repositories.ConsentRepository{}
	consentService := &services.ConsentService{Repo: consentRepo}

	var bankAccountRepo repositories.BankAccountRepositoryInterface = &repositories.BankAccountRepository{}
	bankAccountService := &services.BankAccountService{Repo: bankAccountRepo}

	var membershipRepo repositories.MembershipRepositoryInterface = &repositories.MembershipRepository{}
	var subscriptionRepo repositories.SubscriptionModelsRepositoryInterface = &repositories.SubscriptionModelsRepository{}
	membershipService := &services.MembershipService{Repo: membershipRepo, SubscriptionRepo: subscriptionRepo}

	var licenceRepo repositories.LicenceInterface = &repositories.LicenceRepository{}
	licenceService := &services.LicenceService{Repo: licenceRepo}

	var userRepo repositories.UserRepositoryInterface = &repositories.UserRepository{}
	userService := &services.UserService{Repo: userRepo, Licences: licenceRepo}

	userController := &controllers.UserController{Service: userService, EmailService: emailService, ConsentService: consentService, LicenceService: licenceService, BankAccountService: bankAccountService, MembershipService: membershipService}
	membershipController := &controllers.MembershipController{Service: *membershipService, UserController: userController}
	licenceController := &controllers.LicenceController{Service: *licenceService}
	contactController := &controllers.ContactController{EmailService: emailService}

	router := gin.Default()
	// gin.SetMode(gin.ReleaseMode)
	router.Static(config.Templates.StaticPath, "./style")
	// Load HTML templates
	router.LoadHTMLGlob(filepath.Join(config.Templates.HTMLPath, "*"))

	router.Use(gin.Logger())
	router.Use(middlewares.CORSMiddleware())
	router.Use(middlewares.CSPMiddleware())
	router.Use(middlewares.SecurityHeadersMiddleware())

	limiter := middlewares.NewIPRateLimiter(config.Security.Ratelimits.Limit, config.Security.Ratelimits.Burst)
	router.Use(middlewares.RateLimitMiddleware(limiter))

	routes.RegisterRoutes(router, userController, membershipController, contactController, licenceController)
	validation.SetupValidators()

	logger.Info.Println("Starting server on :8080")
	srv = &http.Server{
		Addr:    ":8080",
		Handler: router,
	}
	go func() {
		if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
			logger.Error.Fatalf("could not start server: %v", err)
		}
	}()
	// Wait for the shutdown signal
	<-shutdownChannel
}

func Shutdown(ctx context.Context) error {
	if srv == nil {
		return nil
	}

	// Graceful shutdown with a timeout
	shutdownCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
	defer cancel()

	// Attempt to shutdown the server
	return srv.Shutdown(shutdownCtx)
}
