package main

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

	"git.kirlllll.ru/volontery/backend/internal/api"
	"git.kirlllll.ru/volontery/backend/internal/config"
	"git.kirlllll.ru/volontery/backend/internal/pkg/jwt"
	"git.kirlllll.ru/volontery/backend/internal/repository"
	"git.kirlllll.ru/volontery/backend/internal/service"
)

func main() {
	if err := run(); err != nil {
		log.Fatal(err)
	}
}

func run() error {
	// Загрузка конфигурации
	cfg, err := config.Load()
	if err != nil {
		return fmt.Errorf("failed to load config: %w", err)
	}

	log.Printf("Starting server in %s mode", cfg.AppEnv)

	// Подключение к базе данных
	ctx := context.Background()
	pool, err := config.NewDBPool(ctx, cfg.DatabaseURL)
	if err != nil {
		return fmt.Errorf("failed to connect to database: %w", err)
	}
	defer pool.Close()

	log.Println("Connected to database")

	// Инициализация репозиториев
	repos := repository.New(pool)

	// Инициализация JWT менеджера
	jwtManager := jwt.NewManager(
		cfg.JWTSecret,
		cfg.JWTAccessTokenTTL,
		cfg.JWTRefreshTokenTTL,
	)

	// Инициализация сервисов
	authService := service.NewAuthService(
		repos.User,
		repos.Auth,
		repos.RBAC,
		jwtManager,
	)

	userService := service.NewUserService(
		repos.User,
		repos.RBAC,
	)

	requestService := service.NewRequestService(
		repos.Request,
	)

	// Создание HTTP сервера
	server := api.NewServer(
		cfg,
		authService,
		userService,
		requestService,
		jwtManager,
	)

	// Настройка HTTP сервера
	addr := fmt.Sprintf("%s:%s", cfg.ServerHost, cfg.ServerPort)
	httpServer := &http.Server{
		Addr:         addr,
		Handler:      server,
		ReadTimeout:  15 * time.Second,
		WriteTimeout: 15 * time.Second,
		IdleTimeout:  60 * time.Second,
	}

	// Канал для обработки ошибок сервера
	serverErrors := make(chan error, 1)

	// Запуск HTTP сервера в горутине
	go func() {
		log.Printf("Server listening on %s", addr)
		serverErrors <- httpServer.ListenAndServe()
	}()

	// Канал для обработки сигналов завершения
	shutdown := make(chan os.Signal, 1)
	signal.Notify(shutdown, os.Interrupt, syscall.SIGTERM)

	// Блокируемся до получения сигнала завершения или ошибки сервера
	select {
	case err := <-serverErrors:
		return fmt.Errorf("server error: %w", err)

	case sig := <-shutdown:
		log.Printf("Received signal %v, starting graceful shutdown", sig)

		// Даем 30 секунд на завершение активных запросов
		ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
		defer cancel()

		if err := httpServer.Shutdown(ctx); err != nil {
			httpServer.Close()
			return fmt.Errorf("failed to gracefully shutdown server: %w", err)
		}

		log.Println("Server stopped gracefully")
	}

	return nil
}
