package main

import (
	"context"
	"fmt"
	"log"
	"net/http"
	_ "net/http/pprof" // MOD-P2-006: Activer pprof pour profiling
	"os"
	"os/signal"
	"syscall"
	"time"

	"github.com/getsentry/sentry-go"
	"github.com/gin-gonic/gin"
	"github.com/joho/godotenv"
	"go.uber.org/zap"

	"veza-backend-api/internal/api"
	"veza-backend-api/internal/config"
	"veza-backend-api/internal/metrics"
	"veza-backend-api/internal/shutdown"

	_ "veza-backend-api/docs" // Import docs for swagger
)

// @title           Veza Backend API
// @version         1.2.0
// @description     Backend API for Veza platform.
// @termsOfService  http://swagger.io/terms/

// @contact.name    API Support
// @contact.url     http://www.veza.app/support
// @contact.email   support@veza.app

// @license.name    Apache 2.0
// @license.url     http://www.apache.org/licenses/LICENSE-2.0.html

// @host            localhost:8080
// @BasePath        /api/v1

// @securityDefinitions.apikey BearerAuth
// @in header
// @name Authorization

func main() {
	// Charger les variables d'environnement
	// NOTE: Do not write to stderr to avoid broken pipe errors with systemd journald
	// The message will be logged by the logger once it's initialized
	_ = godotenv.Load()

	// FIX #1: Supprimer l'initialisation dupliquée du logger
	// Le logger sera initialisé dans config.NewConfig() avec le bon LOG_LEVEL
	// Charger la configuration (qui initialise le logger)
	cfg, err := config.NewConfig()
	if err != nil {
		// CRITICAL: Do not write to stderr or files to avoid broken pipe errors
		// Just exit silently - systemd will capture the exit code
		// The error details will be in the application logs if the logger was initialized
		os.Exit(1)
	}

	// Utiliser le logger de la config
	logger := cfg.Logger
	if logger == nil {
		log.Fatal("❌ Logger non initialisé dans la configuration")
	}

	logger.Info("🚀 Démarrage de Veza Backend API")

	// Valider la configuration
	if err := cfg.Validate(); err != nil {
		logger.Fatal("❌ Configuration invalide", zap.Error(err))
	}

	// Initialiser Sentry si DSN configuré
	if cfg.SentryDsn != "" {
		err := sentry.Init(sentry.ClientOptions{
			Dsn:              cfg.SentryDsn,
			Environment:      cfg.SentryEnvironment,
			TracesSampleRate: cfg.SentrySampleRateTransactions,
			SampleRate:       cfg.SentrySampleRateErrors,
			// AttachStacktrace pour capturer les stack traces
			AttachStacktrace: true,
		})
		if err != nil {
			logger.Warn("❌ Impossible d'initialiser Sentry", zap.Error(err))
		} else {
			logger.Info("✅ Sentry initialisé", zap.String("environment", cfg.SentryEnvironment))
		}
		// Flush les événements Sentry avant shutdown
		defer sentry.Flush(2 * time.Second)
	} else {
		logger.Info("ℹ️ Sentry non configuré (SENTRY_DSN non défini)")
	}

	// Initialisation de la base de données
	db := cfg.Database
	if db == nil {
		logger.Fatal("❌ Base de données non initialisée")
	}
	defer db.Close()

	if err := db.Initialize(); err != nil {
		logger.Fatal("❌ Impossible d'initialiser la base de données", zap.Error(err))
	}

	// MOD-P2-004: Démarrer le collecteur de métriques DB pool
	// Collecte les stats DB pool toutes les 10 secondes et les expose via Prometheus
	metrics.StartDBPoolStatsCollector(db.DB, 10*time.Second)
	logger.Info("✅ Collecteur de métriques DB pool démarré")

	// Fail-Fast: Vérifier RabbitMQ si activé
	if cfg.RabbitMQEnable {
		if cfg.RabbitMQEventBus == nil {
			logger.Fatal("❌ RabbitMQ activé (RABBITMQ_ENABLE=true) mais non initialisé (problème de connexion?)")
		} else {
			// Optionnel: Check connection status if RabbitMQEventBus exposes it
			// For now, assume if initialized it's connected or retrying.
			// If we want STRICT fail fast, we would need to verify connection is Open here.
			logger.Info("✅ RabbitMQ actif")
		}
	} else {
		logger.Info("ℹ️ RabbitMQ désactivé")
	}

	// BE-SVC-017: Créer le gestionnaire de shutdown gracieux
	shutdownManager := shutdown.NewShutdownManager(logger)

	// Démarrer le Job Worker avec contexte pour shutdown gracieux
	var workerCtx context.Context
	var workerCancel context.CancelFunc
	if cfg.JobWorker != nil {
		workerCtx, workerCancel = context.WithCancel(context.Background())
		cfg.JobWorker.Start(workerCtx)
		logger.Info("✅ Job Worker démarré")

		// Enregistrer le Job Worker pour shutdown gracieux
		shutdownManager.Register(shutdown.NewShutdownFunc("job_worker", func(ctx context.Context) error {
			if workerCancel != nil {
				workerCancel()
				// Attendre un peu pour que les workers se terminent
				time.Sleep(2 * time.Second)
			}
			return nil
		}))
	} else {
		logger.Warn("⚠️ Job Worker non initialisé")
	}

	// Configuration du mode Gin
	// Correction: Utilisation directe de la variable d'env car non exposée dans Config
	appEnv := os.Getenv("APP_ENV")
	if appEnv == "production" {
		gin.SetMode(gin.ReleaseMode)
	} else {
		gin.SetMode(gin.DebugMode)
	}

	// Créer le router Gin
	router := gin.New()

	// Middleware globaux (Logger, Recovery) recommandés par ORIGIN
	router.Use(gin.Logger(), gin.Recovery())

	// Configuration des routes
	apiRouter := api.NewAPIRouter(db, cfg) // Instantiate APIRouter
	apiRouter.Setup(router)                // Call its Setup method

	// Configuration du serveur HTTP
	port := fmt.Sprintf("%d", cfg.AppPort)
	if cfg.AppPort == 0 {
		port = "8080"
	}

	server := &http.Server{
		Addr:         fmt.Sprintf(":%s", port),
		Handler:      router,
		ReadTimeout:  30 * time.Second, // Standards ORIGIN
		WriteTimeout: 30 * time.Second,
	}

	// BE-SVC-017: Enregistrer tous les services pour shutdown gracieux
	// Enregistrer le serveur HTTP
	shutdownManager.Register(shutdown.NewShutdownFunc("http_server", func(ctx context.Context) error {
		return server.Shutdown(ctx)
	}))

	// Enregistrer la configuration (ferme DB, Redis, RabbitMQ, etc.)
	shutdownManager.Register(shutdown.NewShutdownFunc("config", func(ctx context.Context) error {
		return cfg.Close()
	}))

	// Enregistrer le logger pour flush final
	shutdownManager.Register(shutdown.NewShutdownFunc("logger", func(ctx context.Context) error {
		if logger != nil {
			return logger.Sync()
		}
		return nil
	}))

	// Enregistrer Sentry pour flush final
	if cfg.SentryDsn != "" {
		shutdownManager.Register(shutdown.NewShutdownFunc("sentry", func(ctx context.Context) error {
			sentry.Flush(2 * time.Second)
			return nil
		}))
	}

	// Gestion de l'arrêt gracieux
	quit := make(chan os.Signal, 1)
	signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)

	go func() {
		logger.Info("🌐 Serveur HTTP démarré", zap.String("port", port))
		if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
			logger.Fatal("❌ Erreur du serveur HTTP", zap.Error(err))
		}
	}()

	// Attendre le signal d'arrêt
	<-quit
	logger.Info("🔄 Signal d'arrêt reçu, démarrage du shutdown gracieux...")

	// BE-SVC-017: Arrêt gracieux coordonné de tous les services
	shutdownCtx, shutdownCancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer shutdownCancel()

	if err := shutdownManager.Shutdown(shutdownCtx); err != nil {
		logger.Error("❌ Erreur lors du shutdown gracieux", zap.Error(err))
	} else {
		logger.Info("✅ Shutdown gracieux terminé avec succès")
	}
}
