package main

import (
	"context"
	"fmt"
	"log"
	"net/http"
	"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/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
	if err := godotenv.Load(); err != nil {
		log.Printf("ℹ️ Note: Fichier .env non trouvé, utilisation des variables d'environnement système")
	}

	// Configuration du logger
	logger, err := zap.NewProduction()
	if err != nil {
		log.Fatalf("Impossible d'initialiser le logger: %v", err)
	}
	defer logger.Sync()

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

	// Charger la configuration
	cfg, err := config.NewConfig()
	if err != nil {
		logger.Fatal("❌ Impossible de charger la configuration", zap.Error(err))
	}

	// 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))
	}

	// Démarrer le Job Worker
	if cfg.JobWorker != nil {
		workerCtx, workerCancel := context.WithCancel(context.Background())
		defer workerCancel()
		cfg.JobWorker.Start(workerCtx)
		logger.Info("✅ Job Worker démarré")
	} 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,
	}

	// 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))
		}
	}()

	<-quit
	logger.Info("🔄 Arrêt du serveur...")

	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()

	if err := server.Shutdown(ctx); err != nil {
		logger.Error("❌ Erreur lors de l'arrêt", zap.Error(err))
	} else {
		logger.Info("✅ Serveur arrêté proprement")
	}
}
