package api

import (
	"context"
	"fmt"
	"net/http" // MOD-P2-006: Pour pprof
	"os"
	"strconv"
	"strings"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/google/uuid"
	"github.com/redis/go-redis/v9"
	"go.uber.org/zap"

	"veza-backend-api/internal/config"
	"veza-backend-api/internal/database"
	"veza-backend-api/internal/handlers" // Single handlers import
	"veza-backend-api/internal/middleware"
	"veza-backend-api/internal/models"

	"veza-backend-api/internal/repositories"

	// swaggerFiles "github.com/swaggo/files" // Uncommented
	// ginSwagger "github.com/swaggo/gin-swagger" // Uncommented

	// Add missing imports.
	swaggerFiles "github.com/swaggo/files"
	ginSwagger "github.com/swaggo/gin-swagger"

	authcore "veza-backend-api/internal/core/auth"
	"veza-backend-api/internal/core/marketplace"
	socialcore "veza-backend-api/internal/core/social"
	trackcore "veza-backend-api/internal/core/track"
	"veza-backend-api/internal/services"
	"veza-backend-api/internal/validators"
	"veza-backend-api/internal/workers"
	// swaggerFiles "github.com/swaggo/files"
	// ginSwagger "github.com/swaggo/gin-swagger"
)

// APIRouter gère la configuration des routes de l'API
type APIRouter struct {
	db                *database.Database
	config            *config.Config
	engine            *gin.Engine
	logger            *zap.Logger
	versionManager    *VersionManager                     // BE-SVC-019: API versioning manager
	monitoringService *services.MonitoringAlertingService // INT-021: API monitoring and alerting
}

// NewAPIRouter crée une nouvelle instance de APIRouter
func NewAPIRouter(db *database.Database, cfg *config.Config) *APIRouter {
	logger := zap.L()
	return &APIRouter{
		db:             db,
		config:         cfg,
		logger:         logger,
		versionManager: NewVersionManager(logger), // BE-SVC-019: Initialize version manager
	}
}

// applyCSRFProtection applique le middleware CSRF à un groupe de routes protégées
// BE-SEC-004: Ensure all POST/PUT/DELETE endpoints validate CSRF tokens
// INT-AUTH-001: Fail-fast in production if Redis unavailable (CSRF requires Redis)
func (r *APIRouter) applyCSRFProtection(protectedGroup *gin.RouterGroup) {
	if r.config == nil {
		if r.logger != nil {
			r.logger.Error("CSRF protection cannot be applied: config is nil")
		}
		// In production, fail-fast (but we can't check env if config is nil)
		// This should not happen in normal operation, but we log it
		return
	}

	if r.config.RedisClient == nil {
		// INT-AUTH-001: In production, Redis MUST be available for CSRF protection
		if r.config.Env == config.EnvProduction {
			if r.logger != nil {
				r.logger.Fatal("CSRF protection requires Redis but Redis is unavailable in production. This is a security requirement.")
			}
			panic("CSRF protection requires Redis in production environment. Redis is unavailable.")
		}
		// In non-production, log warning and continue without CSRF
		if r.logger != nil {
			r.logger.Warn("Redis not available - CSRF protection disabled (non-production environment)")
		}
		return
	}

	// CSRF protection active
	if r.logger != nil {
		r.logger.Info("CSRF protection enabled",
			zap.String("environment", r.config.Env),
		)
	}
	csrfMiddleware := middleware.NewCSRFMiddleware(r.config.RedisClient, r.logger)
	// MVP: Désactiver CSRF en développement
	csrfMiddleware.SetEnvironment(r.config.Env)
	protectedGroup.Use(csrfMiddleware.Middleware())
}

// getUploadConfigWithEnv charge la configuration d'upload depuis l'environnement
// Cette fonction garantit que ENABLE_CLAMAV et CLAMAV_REQUIRED sont correctement appliqués
func getUploadConfigWithEnv() *services.UploadConfig {
	uploadConfig := services.DefaultUploadConfig()

	// Lire ENABLE_CLAMAV depuis l'environnement (défaut: true pour sécurité en production)
	envValue := os.Getenv("ENABLE_CLAMAV")
	fmt.Printf("🔍 [ROUTER] ENABLE_CLAMAV depuis env: '%s'\n", envValue)
	clamAVEnabled := getEnvBool("ENABLE_CLAMAV", true)
	fmt.Printf("🔍 [ROUTER] ENABLE_CLAMAV parsé: %v\n", clamAVEnabled)
	uploadConfig.ClamAVEnabled = clamAVEnabled

	// Lire CLAMAV_REQUIRED depuis l'environnement (défaut: true pour sécurité)
	clamAVRequired := getEnvBool("CLAMAV_REQUIRED", true)
	uploadConfig.ClamAVRequired = clamAVRequired

	fmt.Printf("🔧 [ROUTER] Configuration finale - ClamAVEnabled=%v, ClamAVRequired=%v\n",
		uploadConfig.ClamAVEnabled, uploadConfig.ClamAVRequired)

	return uploadConfig
}

// getEnvBool récupère une variable d'environnement booléenne avec une valeur par défaut
func getEnvBool(key string, defaultValue bool) bool {
	value := os.Getenv(key)
	if value == "" {
		fmt.Printf("🔍 [ROUTER] Variable %s non définie, utilisation défaut: %v\n", key, defaultValue)
		return defaultValue
	}
	// Nettoyer la valeur (trim spaces)
	value = strings.TrimSpace(value)
	fmt.Printf("🔍 [ROUTER] Variable %s='%s' (trimmed)\n", key, value)
	if boolValue, err := strconv.ParseBool(value); err == nil {
		fmt.Printf("🔍 [ROUTER] Variable %s parsée: %v\n", key, boolValue)
		return boolValue
	}
	fmt.Printf("⚠️ [ROUTER] Erreur parsing %s='%s', utilisation défaut: %v\n", key, value, defaultValue)
	return defaultValue
}

// Setup configure toutes les routes de l'API
func (r *APIRouter) Setup(router *gin.Engine) error {
	r.engine = router

	// INT-021: Initialize monitoring and alerting service
	// Initialize monitoring service if Prometheus URL is configured
	prometheusURL := os.Getenv("PROMETHEUS_URL")
	if prometheusURL != "" {
		monitoringConfig := services.MonitoringConfig{
			PrometheusURL: prometheusURL,
			Logger:        r.logger,
		}
		monitoringService, err := services.NewMonitoringAlertingService(monitoringConfig)
		if err != nil {
			r.logger.Warn("Failed to initialize monitoring service", zap.Error(err))
		} else {
			r.monitoringService = monitoringService
			// Add default alert rules
			for _, rule := range services.GetDefaultAlertRules() {
				monitoringService.AddAlertRule(rule)
			}
			// Start monitoring in background
			go func() {
				ctx := context.Background()
				if err := monitoringService.StartMonitoring(ctx, 30*time.Second); err != nil {
					r.logger.Error("Monitoring service stopped", zap.Error(err))
				}
			}()
			r.logger.Info("Monitoring and alerting service initialized", zap.String("prometheus_url", prometheusURL))
		}
	} else {
		r.logger.Info("Monitoring service disabled (PROMETHEUS_URL not configured)")
	}

	// Middlewares globaux
	router.Use(middleware.RequestLogger(r.logger)) // Utilisation du structured logger
	router.Use(middleware.Metrics())               // Prometheus Metrics
	router.Use(middleware.SentryRecover(r.logger)) // Sentry error tracking
	router.Use(middleware.SecurityHeaders())       // MOD-P2-005: Security headers (HSTS, CSP, etc.)

	// INT-021: Add API monitoring middleware to track failures and trigger alerts
	router.Use(middleware.APIMonitoringMiddleware(r.logger, r.monitoringService))

	// MOD-P1-005: Determine if stack traces should be included in logs
	// Stack traces only in dev/DEBUG mode (not in production)
	// Include if: APP_ENV=development OR LOG_LEVEL=DEBUG
	// MOD-P1-005: Determine if stack traces should be included in logs
	// Stack traces only in dev/DEBUG mode (not in production)
	includeStackTrace := r.config.Env == config.EnvDevelopment || r.config.LogLevel == "DEBUG"
	router.Use(middleware.ErrorHandler(r.logger, r.config.ErrorMetrics, includeStackTrace))
	router.Use(middleware.Recovery(r.logger, includeStackTrace))
	// SECURITY: CORS configuration - use config.CORSOrigins strictly (P0-SECURITY)
	// No fallback to CORSDefault() to avoid wildcard in production
	// MOD-P0-001: Apply CORS middleware even if CORSOrigins is empty (strict mode - reject all origins)
	// The middleware itself handles empty list correctly (rejects all origins)
	if r.config != nil {
		// INT-018: Validate CORS configuration before applying middleware
		// In production, this will fail startup if CORS is misconfigured
		if err := middleware.ValidateCORSConfiguration(r.config.CORSOrigins, r.config.Env, r.logger); err != nil {
			// In production, fail startup if CORS is misconfigured
			if r.config.Env == "production" {
				r.logger.Fatal("CORS configuration validation failed - startup aborted", zap.Error(err))
			} else {
				// In development/staging, log error but continue
				r.logger.Error("CORS configuration validation failed", zap.Error(err))
			}
		}

		router.Use(middleware.CORS(r.config.CORSOrigins))
		if len(r.config.CORSOrigins) == 0 {
			r.logger.Warn("CORS origins not configured - strict mode enabled: ALL CORS requests will be rejected.")
		}
	} else {
		// Fallback: if config is nil, apply CORS with empty list (strict mode)
		router.Use(middleware.CORS([]string{}))
		r.logger.Warn("Config is nil - CORS middleware applied in strict mode (reject all origins).")
	}
	router.Use(middleware.RequestID())
	// Global Timeout middleware (PR-6)
	// MOD-P0-003: Removed duplicate timeout middleware registration
	router.Use(middleware.Timeout(r.config.HandlerTimeout))

	// Rate limiting via config.RateLimiter si disponible, sinon utiliser SimpleRateLimiter
	// DÉSACTIVER en développement pour faciliter les tests
	if r.config != nil && r.config.Env != config.EnvDevelopment {
		if r.config.RateLimiter != nil {
			router.Use(r.config.RateLimiter.RateLimitMiddleware())
		} else if r.config.SimpleRateLimiter != nil {
			router.Use(r.config.SimpleRateLimiter.Middleware())
		}
	} else {
		r.logger.Info("Rate limiting disabled in development mode")
	}

	// Swagger Documentation
	router.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
	// INT-DOC-001: Expose /docs endpoint as alias for Swagger UI
	router.GET("/docs", ginSwagger.WrapHandler(swaggerFiles.Handler))
	router.GET("/docs/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))

	// BE-SVC-019: API versioning endpoint (before version middleware)
	router.GET("/api/versions", VersionInfoHandler(r.versionManager))

	// BE-SVC-019: Apply version middleware to API routes
	router.Use(VersionMiddleware(r.versionManager))

	// Routes core publiques (health, metrics, upload info)
	r.setupCorePublicRoutes(router)

	// Setup internal routes (both legacy and modern) before v1 group
	// These need to be on the root router, not under /api/v1
	r.setupInternalRoutes(router)

	// Groupe API v1 (nouveau frontend React)
	v1 := router.Group("/api/v1")
	{
		// Routes core protégées (sessions, uploads, audit, admin, conversations)
		r.setupCoreProtectedRoutes(v1)

		if err := r.setupAuthRoutes(v1); err != nil {
			return err
		}

		// Action 5.2.1.1: Validation endpoint for pre-validation
		r.setupValidateRoutes(v1)

		// Réactivation des routes User et Track pour Phase 1
		r.setupUserRoutes(v1)
		r.setupTrackRoutes(v1)

		// BE-API-007: Roles management routes
		r.setupRoleRoutes(v1)

		// Réactivation des routes Chat pour Phase 4
		r.setupChatRoutes(v1)
		// Réactivation des routes Playlists pour Phase 5
		r.setupPlaylistRoutes(v1)
		// Réactivation des routes Webhooks
		r.setupWebhookRoutes(v1)

		// Marketplace Routes (v1.2.0)
		r.setupMarketplaceRoutes(v1)

		// BE-API-035: Analytics routes
		r.setupAnalyticsRoutes(v1)

		// Social Routes
		r.setupSocialRoutes(v1)
	}

	return nil
}

// Méthodes de configuration des routes par module
// setupMarketplaceRoutes configure les routes de la marketplace
func (r *APIRouter) setupMarketplaceRoutes(router *gin.RouterGroup) {
	uploadDir := r.config.UploadDir
	if uploadDir == "" {
		uploadDir = "uploads/tracks"
	}

	// Storage service (reused from tracks logic)
	storageService := services.NewTrackStorageService(uploadDir, false, r.logger)

	// Marketplace service
	marketService := marketplace.NewService(r.db.GormDB, r.logger, storageService)
	marketHandler := handlers.NewMarketplaceHandler(marketService, r.logger)

	group := router.Group("/marketplace")
	// Public routes
	group.GET("/products", marketHandler.ListProducts)

	// Protected routes
	if r.config.AuthMiddleware != nil {
		protected := group.Group("")
		protected.Use(r.config.AuthMiddleware.RequireAuth())
		// BE-SEC-004: Apply CSRF protection to all state-changing endpoints
		r.applyCSRFProtection(protected)

		// GO-012: Create product requires creator/premium/admin role
		createGroup := protected.Group("")
		createGroup.Use(r.config.AuthMiddleware.RequireContentCreatorRole())
		createGroup.POST("/products", marketHandler.CreateProduct)

		// BE-API-037: Update product endpoint (requires ownership)
		// Resolver: Load product from DB to get its seller_id
		productOwnerResolver := func(c *gin.Context) (uuid.UUID, error) {
			productIDStr := c.Param("id")
			productID, err := uuid.Parse(productIDStr)
			if err != nil {
				return uuid.Nil, err
			}
			// Load product to get seller ID
			product, err := marketService.GetProduct(c.Request.Context(), productID)
			if err != nil {
				return uuid.Nil, err
			}
			return product.SellerID, nil
		}
		protected.PUT("/products/:id", r.config.AuthMiddleware.RequireOwnershipOrAdmin("product", productOwnerResolver), marketHandler.UpdateProduct)

		// BE-API-038: List orders endpoint
		protected.GET("/orders", marketHandler.ListOrders)
		// BE-API-039: Get order details endpoint
		protected.GET("/orders/:id", marketHandler.GetOrder)
		protected.POST("/orders", marketHandler.CreateOrder)
		protected.GET("/download/:product_id", marketHandler.GetDownloadURL)
	}
}

// setupAuthRoutes configure les routes d'authentification avec toutes les dépendances
func (r *APIRouter) setupAuthRoutes(router *gin.RouterGroup) error {
	// 1. Instanciation des dépendances
	emailValidator := validators.NewEmailValidator(r.db.GormDB)
	passwordValidator := validators.NewPasswordValidator()
	passwordService := services.NewPasswordService(r.db, r.logger)
	passwordResetService := services.NewPasswordResetService(r.db, r.logger)
	jwtService, err := services.NewJWTService(r.config.JWTSecret, r.config.JWTIssuer, r.config.JWTAudience)
	if err != nil {
		return fmt.Errorf("failed to initialize JWT service: %w", err)
	}
	refreshTokenService := services.NewRefreshTokenService(r.db.GormDB)
	emailVerificationService := services.NewEmailVerificationService(r.db, r.logger)
	emailService := services.NewEmailService(r.db, r.logger)
	sessionService := services.NewSessionService(r.db, r.logger)

	// 2. Service Auth complet
	authService := authcore.NewAuthService(
		r.db.GormDB,
		emailValidator,
		passwordValidator,
		passwordService,
		jwtService,
		refreshTokenService,
		emailVerificationService,
		passwordResetService,
		emailService,
		r.config.JobWorker, // Passer le JobWorker
		r.logger,
	)

	// BE-SEC-007: Initialize account lockout service and set it on auth service
	if r.config.RedisClient != nil {
		accountLockoutService := services.NewAccountLockoutService(r.config.RedisClient, r.logger)
		authService.SetAccountLockoutService(accountLockoutService)
	} else {
		r.logger.Warn("Redis not available - account lockout disabled")
	}

	// 2.5. User Service for GetMe endpoint
	userRepo := repositories.NewGormUserRepository(r.db.GormDB)
	userService := services.NewUserServiceWithDB(userRepo, r.db.GormDB)

	// 3. Handlers
	authGroup := router.Group("/auth")
	{
		// BE-SEC-005: Apply rate limiting to register endpoint
		// DÉSACTIVER en développement pour faciliter les tests
		registerGroup := authGroup.Group("/register")
		if r.config.EndpointLimiter != nil && r.config.Env != config.EnvDevelopment {
			registerGroup.Use(r.config.EndpointLimiter.RegisterRateLimit())
		}
		registerGroup.POST("", handlers.Register(authService, sessionService, r.logger, r.config))

		// BE-API-001: Initialize 2FA service for login handler
		twoFactorService := services.NewTwoFactorService(r.db, r.logger)

		// Apply rate limiting to login endpoint (PR-3)
		loginGroup := authGroup.Group("/login")
		if r.config.EndpointLimiter != nil {
			loginGroup.Use(r.config.EndpointLimiter.LoginRateLimit())
		}
		loginGroup.POST("", handlers.Login(authService, sessionService, twoFactorService, r.logger, r.config))

		authGroup.POST("/refresh", handlers.Refresh(authService, sessionService, r.logger, r.config))

		// BE-SEC-005: Apply rate limiting to email verification endpoints
		verifyEmailGroup := authGroup.Group("/verify-email")
		if r.config.EndpointLimiter != nil {
			verifyEmailGroup.Use(r.config.EndpointLimiter.VerifyEmailRateLimit())
		}
		verifyEmailGroup.POST("", handlers.VerifyEmail(authService))

		resendVerificationGroup := authGroup.Group("/resend-verification")
		if r.config.EndpointLimiter != nil {
			resendVerificationGroup.Use(r.config.EndpointLimiter.ResendVerificationRateLimit())
		}
		resendVerificationGroup.POST("", handlers.ResendVerification(authService, r.logger))

		authGroup.GET("/check-username", handlers.CheckUsername(authService))

		// BE-API-042: OAuth routes
		// Initialize OAuth service
		jwtSecretBytes := []byte(r.config.JWTSecret)
		oauthService := services.NewOAuthService(r.db, r.logger, jwtSecretBytes)
		// Initialize OAuth configs if credentials are available
		// Note: OAuth credentials should be in environment variables
		// For MVP, we'll get from environment variables directly
		baseURL := os.Getenv("BASE_URL")
		if baseURL == "" {
			baseURL = "http://localhost:8080" // Default for development
		}
		// Get OAuth credentials from environment variables
		googleClientID := os.Getenv("OAUTH_GOOGLE_CLIENT_ID")
		googleClientSecret := os.Getenv("OAUTH_GOOGLE_CLIENT_SECRET")
		githubClientID := os.Getenv("OAUTH_GITHUB_CLIENT_ID")
		githubClientSecret := os.Getenv("OAUTH_GITHUB_CLIENT_SECRET")
		discordClientID := os.Getenv("OAUTH_DISCORD_CLIENT_ID")
		discordClientSecret := os.Getenv("OAUTH_DISCORD_CLIENT_SECRET")

		if googleClientID != "" && googleClientSecret != "" {
			oauthService.InitializeConfigs(googleClientID, googleClientSecret, githubClientID, githubClientSecret, discordClientID, discordClientSecret, baseURL)
		}

		oauthHandler := handlers.NewOAuthHandler(oauthService, r.logger)
		oauthGroup := authGroup.Group("/oauth")
		{
			// Get available OAuth providers
			oauthGroup.GET("/providers", oauthHandler.GetOAuthProviders)
			// Initiate OAuth flow for a provider
			oauthGroup.GET("/:provider", oauthHandler.InitiateOAuth)
			// Handle OAuth callback - BE-API-042: Implement OAuth callback endpoint
			oauthGroup.GET("/:provider/callback", oauthHandler.OAuthCallback)
		}

		// Password reset routes (public)
		// BE-SEC-005: Apply rate limiting to password reset endpoints
		passwordGroup := authGroup.Group("/password")
		if r.config.EndpointLimiter != nil {
			passwordGroup.Use(r.config.EndpointLimiter.PasswordResetRateLimit())
		}
		{
			// BE-SEC-013: Create auditService for password reset handlers
			auditService := services.NewAuditService(r.db, r.logger)
			passwordGroup.POST("/reset-request", handlers.RequestPasswordReset(
				passwordResetService,
				passwordService,
				emailService,
				auditService,
				r.logger,
			))
			passwordGroup.POST("/reset", handlers.ResetPassword(
				passwordResetService,
				passwordService,
				authService,
				sessionService,
				auditService,
				r.logger,
			))
		}

		// Protected routes (authentification JWT requise)
		protected := authGroup.Group("")
		protected.Use(r.config.AuthMiddleware.RequireAuth()) // Changed to RequireAuth()
		// BE-SEC-004: Apply CSRF protection to all state-changing endpoints
		r.applyCSRFProtection(protected)
		{
			protected.POST("/logout", handlers.Logout(authService, sessionService, r.logger, r.config))
			protected.GET("/me", handlers.GetMe(userService))

			// BE-API-001: 2FA routes (reuse service created above)
			twoFactorHandler := handlers.NewTwoFactorHandler(twoFactorService, userService, r.logger)
			{
				protected.POST("/2fa/setup", twoFactorHandler.SetupTwoFactor)
				protected.POST("/2fa/verify", twoFactorHandler.VerifyTwoFactor)
				protected.POST("/2fa/disable", twoFactorHandler.DisableTwoFactor)
				protected.GET("/2fa/status", twoFactorHandler.GetTwoFactorStatus)
			}
		}
	}

	return nil
}

// setupValidateRoutes configures the validation endpoint
// Action 5.2.1.1: Create /api/v1/validate endpoint
func (r *APIRouter) setupValidateRoutes(router *gin.RouterGroup) {
	validateHandler := handlers.NewValidateHandler(r.logger)
	// Public endpoint - no auth required for validation
	router.POST("/validate", validateHandler.Validate)
}

// setupInternalRoutes configure les routes internal (legacy and modern)
// These routes must be on the root router, not under /api/v1
func (r *APIRouter) setupInternalRoutes(router *gin.Engine) {
	// Create track handler for internal routes
	uploadDir := r.config.UploadDir
	if uploadDir == "" {
		uploadDir = "uploads/tracks"
	}
	chunksDir := uploadDir + "/chunks"

	trackService := trackcore.NewTrackService(r.db.GormDB, r.logger, uploadDir)
	// BE-SVC-001: Set cache service for TrackService
	if r.config.CacheService != nil {
		trackService.SetCacheService(r.config.CacheService)
	}
	trackUploadService := services.NewTrackUploadService(r.db.GormDB, r.logger)
	var redisClient *redis.Client
	if r.config != nil {
		redisClient = r.config.RedisClient
	}
	chunkService := services.NewTrackChunkService(chunksDir, redisClient, r.logger)
	likeService := services.NewTrackLikeService(r.db.GormDB, r.logger)
	streamService := services.NewStreamService(r.config.StreamServerURL, r.logger)

	trackHandler := trackcore.NewTrackHandler(
		trackService,
		trackUploadService,
		chunkService,
		likeService,
		streamService,
	)

	// Deprecated /internal routes (legacy, on root router)
	internalDeprecated := router.Group("/internal")
	internalDeprecated.Use(middleware.DeprecationWarning(r.logger))
	{
		internalDeprecated.POST("/tracks/:id/stream-ready", trackHandler.HandleStreamCallback)
	}

	// New /api/v1/internal routes (modern, on root router)
	v1Internal := router.Group("/api/v1/internal")
	{
		v1Internal.POST("/tracks/:id/stream-ready", trackHandler.HandleStreamCallback)
	}
}

// setupUserRoutes configure les routes utilisateur
func (r *APIRouter) setupUserRoutes(router *gin.RouterGroup) {
	userRepo := repositories.NewGormUserRepository(r.db.GormDB)
	userService := services.NewUserServiceWithDB(userRepo, r.db.GormDB)
	profileHandler := handlers.NewProfileHandler(userService, r.logger)
	// MOD-P1-003: Set permission service for admin check in ownership verification
	if r.config != nil && r.config.PermissionService != nil {
		profileHandler.SetPermissionService(r.config.PermissionService)
	}
	// BE-API-017: Initialize SocialService for follow/unfollow functionality
	socialService := services.NewSocialService(r.db, r.logger)
	profileHandler.SetSocialService(socialService)

	users := router.Group("/users")
	{
		users.GET("", profileHandler.ListUsers) // BE-API-040: User list endpoint
		users.GET("/:id", profileHandler.GetProfile)
		users.GET("/by-username/:username", profileHandler.GetProfileByUsername)
		users.GET("/search", profileHandler.SearchUsers) // BE-API-008: User search endpoint

		// Protected routes
		if r.config.AuthMiddleware != nil {
			protected := users.Group("")
			protected.Use(r.config.AuthMiddleware.RequireAuth())
			// BE-SEC-004: Apply CSRF protection to all state-changing endpoints
			r.applyCSRFProtection(protected)

			// T0231/T0232: User settings endpoints (uses authenticated user, no :id)
			settingsHandler := handlers.NewSettingsHandler(userService, r.logger)
			protected.GET("/settings", settingsHandler.GetSettings)    // GET /api/v1/users/settings
			protected.PUT("/settings", settingsHandler.UpdateSettings) // PUT /api/v1/users/settings

			// MOD-P0-003: Apply ownership middleware for PUT /users/:id
			// Resolver: For users, the :id param is directly the user_id
			userOwnerResolver := func(c *gin.Context) (uuid.UUID, error) {
				userIDStr := c.Param("id")
				return uuid.Parse(userIDStr)
			}
			protected.PUT("/:id", r.config.AuthMiddleware.RequireOwnershipOrAdmin("user", userOwnerResolver), profileHandler.UpdateProfile)
			// BE-API-041: Delete user endpoint (soft delete)
			protected.DELETE("/:id", r.config.AuthMiddleware.RequireOwnershipOrAdmin("user", userOwnerResolver), profileHandler.DeleteUser)

			protected.GET("/:id/completion", profileHandler.GetProfileCompletion)

			// BE-API-017: User follow/unfollow endpoints
			protected.POST("/:id/follow", profileHandler.FollowUser)     // Follow user endpoint
			protected.DELETE("/:id/follow", profileHandler.UnfollowUser) // Unfollow user endpoint

			// BE-API-018: User block/unblock endpoints
			protected.POST("/:id/block", profileHandler.BlockUser)     // Block user endpoint
			protected.DELETE("/:id/block", profileHandler.UnblockUser) // Unblock user endpoint

			// BE-API-007: User role assignment routes
			roleService := services.NewRoleService(r.db.GormDB)
			roleHandler := handlers.NewRoleHandler(roleService, r.logger)
			protected.POST("/:id/roles", roleHandler.AssignRole)           // POST /api/v1/users/:id/roles
			protected.DELETE("/:id/roles/:roleId", roleHandler.RevokeRole) // DELETE /api/v1/users/:id/roles/:roleId

			// BE-API-021: Avatar upload endpoint
			// BE-API-022: Avatar delete endpoint
			avatarUploadDir := r.config.UploadDir
			if avatarUploadDir == "" {
				avatarUploadDir = "uploads/avatars"
			}
			imageService := services.NewImageService(avatarUploadDir)
			avatarHandler := handlers.NewAvatarHandler(imageService, userService)
			protected.POST("/:id/avatar", avatarHandler.UploadAvatar)   // BE-API-021: Upload avatar endpoint
			protected.DELETE("/:id/avatar", avatarHandler.DeleteAvatar) // BE-API-022: Delete avatar endpoint

			// BE-API-027: User liked tracks endpoint
			// Initialize TrackLikeService and minimal TrackHandler for user liked tracks
			uploadDir := r.config.UploadDir
			if uploadDir == "" {
				uploadDir = "uploads/tracks"
			}
			likeService := services.NewTrackLikeService(r.db.GormDB, r.logger)
			trackService := trackcore.NewTrackService(r.db.GormDB, r.logger, uploadDir)
			// BE-SVC-001: Set cache service for TrackService
			if r.config.CacheService != nil {
				trackService.SetCacheService(r.config.CacheService)
			}
			trackUploadService := services.NewTrackUploadService(r.db.GormDB, r.logger)
			var redisClient *redis.Client
			if r.config != nil {
				redisClient = r.config.RedisClient
			}
			chunksDir := uploadDir + "/chunks"
			chunkService := services.NewTrackChunkService(chunksDir, redisClient, r.logger)
			streamService := services.NewStreamService(r.config.StreamServerURL, r.logger)
			trackHandlerForLikes := trackcore.NewTrackHandler(
				trackService,
				trackUploadService,
				chunkService,
				likeService,
				streamService,
			)
			protected.GET("/:id/likes", trackHandlerForLikes.GetUserLikedTracks) // BE-API-027: Get user liked tracks endpoint

			// BE-SVC-022: Data export endpoint for GDPR compliance
			dataExportService := services.NewDataExportService(r.db.GormDB, r.logger)
			exportHandler := func(c *gin.Context) {
				userID, exists := c.Get("user_id")
				if !exists {
					c.JSON(http.StatusUnauthorized, gin.H{"error": "User ID not found"})
					return
				}

				userUUID, ok := userID.(uuid.UUID)
				if !ok {
					c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid user ID"})
					return
				}

				// Export user data as JSON file
				jsonData, err := dataExportService.ExportUserDataAsJSON(c.Request.Context(), userUUID)
				if err != nil {
					r.logger.Error("Failed to export user data", zap.Error(err), zap.String("user_id", userUUID.String()))
					c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to export user data"})
					return
				}

				// Set headers for file download
				filename := "veza-data-export-" + time.Now().Format("2006-01-02T15-04-05") + ".json"
				c.Header("Content-Type", "application/json")
				c.Header("Content-Disposition", `attachment; filename="`+filename+`"`)
				c.Header("Content-Length", strconv.Itoa(len(jsonData)))

				// Send JSON file
				c.Data(http.StatusOK, "application/json", jsonData)
			}
			protected.GET("/me/export", exportHandler) // BE-SVC-022: Export user data endpoint
		}
	}
}

// setupRoleRoutes configure les routes de gestion des rôles
// BE-API-007: Implement roles management endpoints
func (r *APIRouter) setupRoleRoutes(router *gin.RouterGroup) {
	roleService := services.NewRoleService(r.db.GormDB)
	roleHandler := handlers.NewRoleHandler(roleService, r.logger)

	// Roles routes
	roles := router.Group("/roles")
	{
		// Protected routes
		if r.config.AuthMiddleware != nil {
			protected := roles.Group("")
			protected.Use(r.config.AuthMiddleware.RequireAuth())
			// BE-SEC-004: Apply CSRF protection to all state-changing endpoints
			r.applyCSRFProtection(protected)
			{
				protected.GET("", roleHandler.GetRoles)    // GET /api/v1/roles
				protected.GET("/:id", roleHandler.GetRole) // GET /api/v1/roles/:id
			}
		}
	}
}

// setupTrackRoutes configure les routes de gestion des tracks
func (r *APIRouter) setupTrackRoutes(router *gin.RouterGroup) {
	uploadDir := r.config.UploadDir
	if uploadDir == "" {
		uploadDir = "uploads/tracks"
	}
	chunksDir := uploadDir + "/chunks"

	trackService := trackcore.NewTrackService(r.db.GormDB, r.logger, uploadDir)
	// BE-SVC-001: Set cache service for TrackService
	if r.config.CacheService != nil {
		trackService.SetCacheService(r.config.CacheService)
	}
	trackUploadService := services.NewTrackUploadService(r.db.GormDB, r.logger)
	var redisClient *redis.Client
	if r.config != nil {
		redisClient = r.config.RedisClient
	}
	chunkService := services.NewTrackChunkService(chunksDir, redisClient, r.logger)
	likeService := services.NewTrackLikeService(r.db.GormDB, r.logger)
	streamService := services.NewStreamService(r.config.StreamServerURL, r.logger)

	trackHandler := trackcore.NewTrackHandler(
		trackService,
		trackUploadService,
		chunkService,
		likeService,
		streamService,
	)
	// MOD-P1-003: Set permission service for admin check in ownership verification
	if r.config != nil && r.config.PermissionService != nil {
		trackHandler.SetPermissionService(r.config.PermissionService)
	}
	// MOD-P1-001: Set upload validator for ClamAV scan before persistence
	// CORRECTION: Charger la config depuis l'environnement pour respecter ENABLE_CLAMAV
	uploadConfig := getUploadConfigWithEnv()
	fmt.Printf("🔧 [ROUTER] Configuration upload chargée - ClamAVEnabled=%v, ClamAVRequired=%v\n",
		uploadConfig.ClamAVEnabled, uploadConfig.ClamAVRequired)
	uploadValidator, err := services.NewUploadValidator(uploadConfig, r.logger)
	if err != nil {
		r.logger.Warn("Upload validator created with ClamAV unavailable - uploads will be rejected", zap.Error(err))
		uploadConfig.ClamAVEnabled = false
		uploadValidator, _ = services.NewUploadValidator(uploadConfig, r.logger)
	}
	trackHandler.SetUploadValidator(uploadValidator)

	// BE-API-009: Initialize TrackSearchService for track search functionality
	trackSearchService := services.NewTrackSearchService(r.db.GormDB)
	trackHandler.SetSearchService(trackSearchService)

	// BE-API-014: Initialize TrackVersionService for track version restore functionality
	trackVersionService := services.NewTrackVersionService(r.db.GormDB, r.logger, uploadDir)
	trackHandler.SetVersionService(trackVersionService)

	// BE-API-019: Initialize PlaybackAnalyticsService for track play analytics
	playbackAnalyticsService := services.NewPlaybackAnalyticsService(r.db.GormDB, r.logger)
	trackHandler.SetPlaybackAnalyticsService(playbackAnalyticsService)

	tracks := router.Group("/tracks")
	{
		// Public routes
		tracks.GET("", trackHandler.ListTracks)
		tracks.GET("/search", trackHandler.SearchTracks) // BE-API-009: Track search endpoint
		tracks.GET("/:id", trackHandler.GetTrack)
		tracks.GET("/:id/stats", trackHandler.GetTrackStats)
		tracks.GET("/:id/history", trackHandler.GetTrackHistory)
		tracks.GET("/:id/download", trackHandler.DownloadTrack)
		tracks.GET("/shared/:token", trackHandler.GetSharedTrack)

		// Protected routes
		if r.config.AuthMiddleware != nil {
			protected := tracks.Group("")
			protected.Use(r.config.AuthMiddleware.RequireAuth())
			// BE-SEC-004: Apply CSRF protection to all state-changing endpoints
			r.applyCSRFProtection(protected)

			// GO-012: Upload track requires creator/premium/admin role
			uploadGroup := protected.Group("")
			uploadGroup.Use(r.config.AuthMiddleware.RequireContentCreatorRole())
			uploadGroup.POST("", trackHandler.UploadTrack)

			// MOD-P0-003: Apply ownership middleware for PUT/DELETE /tracks/:id
			// Resolver: Load track from DB to get its user_id
			trackOwnerResolver := func(c *gin.Context) (uuid.UUID, error) {
				trackIDStr := c.Param("id")
				trackID, err := uuid.Parse(trackIDStr)
				if err != nil {
					return uuid.Nil, err
				}
				// Load track to get owner ID
				track, err := trackService.GetTrackByID(c.Request.Context(), trackID)
				if err != nil {
					return uuid.Nil, err
				}
				return track.UserID, nil
			}
			protected.PUT("/:id", r.config.AuthMiddleware.RequireOwnershipOrAdmin("track", trackOwnerResolver), trackHandler.UpdateTrack)
			protected.DELETE("/:id", r.config.AuthMiddleware.RequireOwnershipOrAdmin("track", trackOwnerResolver), trackHandler.DeleteTrack)

			// Upload
			protected.GET("/:id/status", trackHandler.GetUploadStatus)
			protected.POST("/initiate", trackHandler.InitiateChunkedUpload)
			protected.POST("/chunk", trackHandler.UploadChunk)
			protected.POST("/complete", trackHandler.CompleteChunkedUpload)
			protected.GET("/quota/:id", trackHandler.GetUploadQuota)
			protected.GET("/resume/:uploadId", trackHandler.ResumeUpload)

			// Batch operations
			protected.POST("/batch/delete", trackHandler.BatchDeleteTracks)
			protected.POST("/batch/update", trackHandler.BatchUpdateTracks)

			// Social
			protected.POST("/:id/like", trackHandler.LikeTrack)
			protected.DELETE("/:id/like", trackHandler.UnlikeTrack)
			protected.GET("/:id/likes", trackHandler.GetTrackLikes)

			// Sharing
			protected.POST("/:id/share", trackHandler.CreateShare)
			protected.DELETE("/share/:id", trackHandler.RevokeShare)

			// Versions
			protected.POST("/:id/versions/:versionId/restore", trackHandler.RestoreVersion) // BE-API-014: Restore track version endpoint

			// Analytics
			protected.POST("/:id/play", trackHandler.RecordPlay) // BE-API-019: Record track play event endpoint

			// HLS Streaming
			// BE-API-020: HLS stream info and status endpoints
			hlsOutputDir := r.config.UploadDir
			if hlsOutputDir == "" {
				hlsOutputDir = "uploads/tracks"
			}
			hlsService := services.NewHLSService(r.db.GormDB, hlsOutputDir, r.logger)
			hlsHandler := handlers.NewHLSHandler(hlsService)
			tracks.GET("/:id/hls/info", hlsHandler.GetStreamInfo)     // BE-API-020: Get HLS stream info
			tracks.GET("/:id/hls/status", hlsHandler.GetStreamStatus) // BE-API-020: Get HLS stream status
		}
	}

	// BE-API-013: Setup comment routes
	commentService := services.NewCommentService(r.db.GormDB, r.logger)
	commentHandler := handlers.NewCommentHandler(commentService, r.logger)

	// Comments routes - public GET, protected POST/DELETE
	comments := router.Group("/tracks")
	{
		// Public: Get comments for a track
		comments.GET("/:id/comments", commentHandler.GetComments) // BE-API-013: GET /api/v1/tracks/:id/comments

		// Protected: Create and delete comments
		if r.config.AuthMiddleware != nil {
			protected := comments.Group("")
			protected.Use(r.config.AuthMiddleware.RequireAuth())
			// BE-SEC-004: Apply CSRF protection to all state-changing endpoints
			r.applyCSRFProtection(protected)
			{
				protected.POST("/:id/comments", commentHandler.CreateComment) // BE-API-013: POST /api/v1/tracks/:id/comments
			}
		}
	}

	// Comments routes - protected DELETE
	commentsProtected := router.Group("/comments")
	{
		if r.config.AuthMiddleware != nil {
			commentsProtected.Use(r.config.AuthMiddleware.RequireAuth())
			// BE-SEC-004: Apply CSRF protection to all state-changing endpoints
			r.applyCSRFProtection(commentsProtected)
			{
				commentsProtected.DELETE("/:id", commentHandler.DeleteComment) // BE-API-013: DELETE /api/v1/comments/:id
			}
		}
	}

	// Note: Internal routes are now set up in setupInternalRoutes() to avoid
	// path prefix issues when setupTrackRoutes is called with a RouterGroup
	// BE-API-027: User liked tracks route moved to setupUserRoutes
}

// setupChatRoutes configure les routes de chat
func (r *APIRouter) setupChatRoutes(router *gin.RouterGroup) {
	// BE-API-006: Use NewChatServiceWithDB to enable stats functionality
	chatService := services.NewChatServiceWithDB(r.config.ChatJWTSecret, r.db.GormDB, r.logger)
	userRepo := repositories.NewGormUserRepository(r.db.GormDB)
	userService := services.NewUserServiceWithDB(userRepo, r.db.GormDB)

	chatHandler := handlers.NewChatHandler(chatService, userService, r.logger)

	chat := router.Group("/chat")
	{
		if r.config.AuthMiddleware != nil {
			chat.Use(r.config.AuthMiddleware.RequireAuth())
			// BE-SEC-004: Apply CSRF protection to all state-changing endpoints
			r.applyCSRFProtection(chat)
			chat.POST("/token", chatHandler.GetToken)
			chat.GET("/stats", chatHandler.GetStats) // BE-API-006: Chat stats endpoint
		}
	}
}

// setupPlaylistRoutes configure les routes pour les playlists
func (r *APIRouter) setupPlaylistRoutes(router *gin.RouterGroup) {
	playlistRepo := repositories.NewPlaylistRepository(r.db.GormDB)
	playlistTrackRepo := repositories.NewPlaylistTrackRepository(r.db.GormDB)
	playlistCollaboratorRepo := repositories.NewPlaylistCollaboratorRepository(r.db.GormDB)
	userRepo := repositories.NewGormUserRepository(r.db.GormDB)

	playlistService := services.NewPlaylistService(
		playlistRepo,
		playlistTrackRepo,
		playlistCollaboratorRepo,
		userRepo,
		r.logger,
	)

	// BE-API-004: Initialize PlaylistShareService for share link functionality
	playlistShareService := services.NewPlaylistShareService(r.db.GormDB)
	playlistService.SetPlaylistShareService(playlistShareService)

	// BE-API-005: Initialize PlaylistFollowService for recommendations functionality
	playlistFollowService := services.NewPlaylistFollowService(r.db.GormDB, r.logger)
	playlistService.SetPlaylistFollowService(playlistFollowService)

	playlistHandler := handlers.NewPlaylistHandler(playlistService, r.db.GormDB, r.logger)
	// BE-API-005: Inject PlaylistFollowService into handler for recommendations
	playlistHandler.SetPlaylistFollowService(playlistFollowService)

	// Protected routes for playlists
	playlists := router.Group("/playlists")
	if r.config.AuthMiddleware != nil {
		playlists.Use(r.config.AuthMiddleware.RequireAuth())
		// BE-SEC-004: Apply CSRF protection to all state-changing endpoints
		r.applyCSRFProtection(playlists)
		{
			playlists.GET("", playlistHandler.GetPlaylists)
			playlists.POST("", playlistHandler.CreatePlaylist)
			playlists.GET("/search", playlistHandler.SearchPlaylists)             // BE-API-003: Playlist search endpoint
			playlists.GET("/recommendations", playlistHandler.GetRecommendations) // BE-API-005: Playlist recommendations endpoint
			playlists.GET("/:id", playlistHandler.GetPlaylist)

			// BE-SEC-003: Apply ownership middleware for PUT/DELETE /playlists/:id
			// Resolver: Load playlist from DB to get its user_id
			playlistOwnerResolver := func(c *gin.Context) (uuid.UUID, error) {
				playlistIDStr := c.Param("id")
				playlistID, err := uuid.Parse(playlistIDStr)
				if err != nil {
					return uuid.Nil, err
				}
				// Load playlist to get owner ID
				playlist, err := playlistRepo.GetByID(c.Request.Context(), playlistID)
				if err != nil {
					return uuid.Nil, err
				}
				return playlist.UserID, nil
			}
			playlists.PUT("/:id", r.config.AuthMiddleware.RequireOwnershipOrAdmin("playlist", playlistOwnerResolver), playlistHandler.UpdatePlaylist)
			playlists.DELETE("/:id", r.config.AuthMiddleware.RequireOwnershipOrAdmin("playlist", playlistOwnerResolver), playlistHandler.DeletePlaylist)

			// Playlist Tracks
			playlists.POST("/:id/tracks", playlistHandler.AddTrack)
			playlists.DELETE("/:id/tracks/:track_id", playlistHandler.RemoveTrack)
			playlists.PUT("/:id/tracks/reorder", playlistHandler.ReorderTracks)

			// Playlist Collaborators
			// BE-API-002: Add collaborator routes with ownership checks
			// POST and DELETE require ownership (enforced by service layer, but middleware adds extra security)
			playlists.POST("/:id/collaborators", r.config.AuthMiddleware.RequireOwnershipOrAdmin("playlist", playlistOwnerResolver), playlistHandler.AddCollaborator)
			playlists.GET("/:id/collaborators", playlistHandler.GetCollaborators) // GET accessible to collaborators (service checks permissions)
			playlists.PUT("/:id/collaborators/:userId", r.config.AuthMiddleware.RequireOwnershipOrAdmin("playlist", playlistOwnerResolver), playlistHandler.UpdateCollaboratorPermission)
			playlists.DELETE("/:id/collaborators/:userId", r.config.AuthMiddleware.RequireOwnershipOrAdmin("playlist", playlistOwnerResolver), playlistHandler.RemoveCollaborator)

			// BE-API-004: Playlist share link endpoint
			playlists.POST("/:id/share", r.config.AuthMiddleware.RequireOwnershipOrAdmin("playlist", playlistOwnerResolver), playlistHandler.CreateShareLink)
		}
	}
}

// setupWebhookRoutes configure les routes pour les webhooks
func (r *APIRouter) setupWebhookRoutes(router *gin.RouterGroup) {
	webhookService := services.NewWebhookService(r.db.GormDB, r.logger, r.config.JWTSecret)

	webhookWorker := workers.NewWebhookWorker(
		r.db.GormDB,
		webhookService,
		r.logger,
		100, // Queue size
		5,   // Workers
		3,   // Max retries
	)

	// Start worker in background
	go webhookWorker.Start(context.Background())

	webhookHandler := handlers.NewWebhookHandler(webhookService, webhookWorker, r.logger)

	webhooks := router.Group("/webhooks")
	if r.config.AuthMiddleware != nil {
		webhooks.Use(r.config.AuthMiddleware.RequireAuth())
		// BE-SEC-004: Apply CSRF protection to all state-changing endpoints
		r.applyCSRFProtection(webhooks)
	}
	{
		webhooks.POST("", webhookHandler.RegisterWebhook())
		webhooks.GET("", webhookHandler.ListWebhooks())
		webhooks.DELETE("/:id", webhookHandler.DeleteWebhook())
		webhooks.GET("/stats", webhookHandler.GetWebhookStats())
		webhooks.POST("/:id/test", webhookHandler.TestWebhook())
		// BE-SEC-012: Regenerate API key endpoint
		webhooks.POST("/:id/regenerate-key", webhookHandler.RegenerateAPIKey())
	}
}

// setupAnalyticsRoutes configure les routes pour les analytics
// BE-API-035: Implement analytics events endpoint
func (r *APIRouter) setupAnalyticsRoutes(router *gin.RouterGroup) {
	if r.db == nil || r.db.GormDB == nil {
		return
	}

	// Initialize analytics service
	analyticsService := services.NewAnalyticsService(r.db.GormDB, r.logger)
	analyticsHandler := handlers.NewAnalyticsHandler(analyticsService, r.logger)

	// Set JobWorker if available
	if r.config != nil && r.config.JobWorker != nil {
		analyticsHandler.SetJobWorker(r.config.JobWorker)
	}

	analytics := router.Group("/analytics")
	if r.config != nil && r.config.AuthMiddleware != nil {
		analytics.Use(r.config.AuthMiddleware.RequireAuth())
		// BE-SEC-004: Apply CSRF protection to all state-changing endpoints
		r.applyCSRFProtection(analytics)
	}
	{
		// BE-API-037: GET /analytics - Aggregated analytics endpoint
		analytics.GET("", analyticsHandler.GetAnalytics)
		// BE-API-035: Analytics events endpoint
		analytics.POST("/events", analyticsHandler.RecordEvent)
		// BE-API-036: Track analytics dashboard endpoint
		analytics.GET("/tracks/:id", analyticsHandler.GetTrackAnalyticsDashboard)
	}
}

// setupCorePublicRoutes configure les routes publiques core (health, metrics, upload info)
func (r *APIRouter) setupCorePublicRoutes(router *gin.Engine) {
	// Health check handlers
	var healthCheckHandler gin.HandlerFunc
	var livenessHandler gin.HandlerFunc
	var readinessHandler gin.HandlerFunc

	if r.db != nil && r.db.GormDB != nil {
		var redisClient interface{}
		if r.config != nil {
			redisClient = r.config.RedisClient
		}
		var rabbitMQEventBus interface{}
		if r.config != nil {
			rabbitMQEventBus = r.config.RabbitMQEventBus
		}
		var env string
		if r.config != nil {
			env = r.config.Env
		}
		// BE-SVC-016: Pass additional services for detailed health checks
		var s3Service interface{}
		var jobWorker interface{}
		var emailSender interface{}
		if r.config != nil {
			s3Service = r.config.S3StorageService
			jobWorker = r.config.JobWorker
			emailSender = r.config.EmailSender
		}
		healthHandler := handlers.NewHealthHandlerWithServices(
			r.db.GormDB,
			r.logger,
			redisClient,
			rabbitMQEventBus,
			env,
			s3Service,
			jobWorker,
			emailSender,
		)
		healthCheckHandler = healthHandler.Check
		livenessHandler = healthHandler.Liveness
		readinessHandler = healthHandler.Readiness
	} else {
		healthCheckHandler = handlers.SimpleHealthCheck
		livenessHandler = handlers.SimpleHealthCheck
		readinessHandler = handlers.SimpleHealthCheck
	}

	// Deprecated Public Core Routes - apply deprecation middleware only to specific routes
	// Use a wrapper function to apply middleware to individual routes
	deprecationMW := middleware.DeprecationWarning(r.logger)

	// INT-021: Add health check monitoring middleware
	healthMonitoringMW := middleware.HealthCheckMonitoring(r.logger, r.monitoringService)

	// Wrap handlers with deprecation middleware for legacy routes only
	router.GET("/health", deprecationMW, healthMonitoringMW, healthCheckHandler)
	router.GET("/healthz", deprecationMW, healthMonitoringMW, livenessHandler)
	router.GET("/readyz", deprecationMW, healthMonitoringMW, readinessHandler)
	router.GET("/metrics", deprecationMW, handlers.PrometheusMetrics())
	if r.config != nil && r.config.ErrorMetrics != nil {
		router.GET("/metrics/aggregated", deprecationMW, handlers.AggregatedMetrics(r.config.ErrorMetrics))
	}
	router.GET("/system/metrics", deprecationMW, handlers.SystemMetrics)

	// New /api/v1 Public Core Routes
	v1Public := router.Group("/api/v1")
	{
		v1Public.GET("/health", healthCheckHandler)
		v1Public.GET("/healthz", livenessHandler)
		v1Public.GET("/readyz", readinessHandler)

		// Status endpoint (comprehensive health check)
		if r.db != nil && r.db.GormDB != nil {
			var redisClient interface{}
			if r.config != nil {
				redisClient = r.config.RedisClient
			}
			chatServerURL := ""
			streamServerURL := ""
			if r.config != nil {
				chatServerURL = r.config.ChatServerURL
				streamServerURL = r.config.StreamServerURL
			}
			// Get build info from environment or defaults
			getEnv := func(key, defaultValue string) string {
				if value := os.Getenv(key); value != "" {
					return value
				}
				return defaultValue
			}
			version := getEnv("APP_VERSION", "v1.0.0")
			gitCommit := getEnv("GIT_COMMIT", "unknown")
			buildTime := getEnv("BUILD_TIME", "")
			environment := ""
			if r.config != nil {
				environment = r.config.Env
			}
			statusHandler := handlers.NewStatusHandler(
				r.db.GormDB,
				r.logger,
				redisClient,
				chatServerURL,
				streamServerURL,
				version,
				gitCommit,
				buildTime,
				environment,
			)
			v1Public.GET("/status", statusHandler.GetStatus)
		}

		v1Public.GET("/metrics", handlers.PrometheusMetrics())
		if r.config != nil && r.config.ErrorMetrics != nil {
			v1Public.GET("/metrics/aggregated", handlers.AggregatedMetrics(r.config.ErrorMetrics))
		}
		v1Public.GET("/system/metrics", handlers.SystemMetrics)

		// Upload info endpoints (public, already in /api/v1)
		// MOD-P1-001-REFINEMENT: Permettre démarrage même si ClamAV down
		if r.db != nil && r.db.GormDB != nil {
			// CORRECTION: Charger la config depuis l'environnement pour respecter ENABLE_CLAMAV
			uploadConfig := getUploadConfigWithEnv()
			uploadValidator, err := services.NewUploadValidator(uploadConfig, r.logger)
			if err != nil {
				r.logger.Warn("Upload validator created with ClamAV unavailable - uploads will be rejected", zap.Error(err))
				// Créer un validateur minimal pour permettre les endpoints info
				uploadConfig.ClamAVEnabled = false
				uploadValidator, _ = services.NewUploadValidator(uploadConfig, r.logger)
			}
			auditService := services.NewAuditService(r.db, r.logger)
			trackUploadService := services.NewTrackUploadService(r.db.GormDB, r.logger)
			uploadHandler := handlers.NewUploadHandler(uploadValidator, auditService, trackUploadService, r.logger, r.config.MaxConcurrentUploads)
			v1Public.GET("/upload/limits", uploadHandler.GetUploadLimits())
			v1Public.GET("/upload/validate-type", uploadHandler.ValidateFileType())
		}

		// Frontend logging endpoint (public - frontend needs to send logs)
		if r.config != nil {
			frontendLogHandler, err := handlers.NewFrontendLogHandler(r.config, r.logger)
			if err != nil {
				r.logger.Warn("Failed to create frontend log handler, frontend logs will not be stored", zap.Error(err))
			} else {
				v1Public.POST("/logs/frontend", frontendLogHandler.ReceiveLog)
				r.logger.Info("Frontend logging endpoint enabled", zap.String("endpoint", "/api/v1/logs/frontend"))
			}
		}
	}
}

// setupCoreProtectedRoutes configure les routes protégées core (sessions, uploads, audit, admin, conversations)
func (r *APIRouter) setupCoreProtectedRoutes(v1 *gin.RouterGroup) {
	if r.db == nil || r.db.GormDB == nil || r.config == nil {
		return
	}

	// Route CSRF token (doit être accessible sans authentification pour le login)
	// Doit être enregistrée AVANT le groupe protected pour ne pas hériter ses middlewares
	csrfMiddleware := middleware.NewCSRFMiddleware(r.config.RedisClient, r.logger)
	csrfMiddleware.SetEnvironment(r.config.Env)
	csrfHandler := handlers.NewCSRFHandler(csrfMiddleware, r.logger)
	if r.config.AuthMiddleware != nil {
		v1.GET("/csrf-token", r.config.AuthMiddleware.OptionalAuth(), csrfHandler.GetCSRFToken())
	} else {
		v1.GET("/csrf-token", csrfHandler.GetCSRFToken())
	}

	// Middleware d'authentification pour routes protégées
	protected := v1.Group("/")
	if r.config.AuthMiddleware != nil {
		protected.Use(r.config.AuthMiddleware.RequireAuth())
	}

	// Services nécessaires
	sessionService := services.NewSessionService(r.db, r.logger)

	// CSRF Middleware (si Redis est disponible)
	if r.config.RedisClient != nil {
		// Appliquer le middleware CSRF à toutes les routes protégées
		protected.Use(csrfMiddleware.Middleware())

		// INT-AUTH-001: Log explicit activation
		r.logger.Info("CSRF protection enabled for core protected routes",
			zap.String("environment", r.config.Env),
		)
	} else {
		// INT-AUTH-001: In production, fail-fast if Redis unavailable
		if r.config.Env == config.EnvProduction {
			r.logger.Fatal("CSRF protection requires Redis but Redis is unavailable in production. This is a security requirement.")
			panic("CSRF protection requires Redis in production environment. Redis is unavailable.")
		}
		// In non-production, log warning and continue without CSRF
		r.logger.Warn("Redis not available - CSRF protection disabled (non-production environment)",
			zap.String("environment", r.config.Env),
		)
	}
	// CORRECTION: Charger la config depuis l'environnement pour respecter ENABLE_CLAMAV
	uploadConfig := getUploadConfigWithEnv()
	// MOD-P1-001-REFINEMENT: Permettre démarrage même si ClamAV down
	uploadValidator, err := services.NewUploadValidator(uploadConfig, r.logger)
	if err != nil {
		r.logger.Warn("Upload validator created with ClamAV unavailable - uploads will be rejected", zap.Error(err))
		// Créer un validateur minimal pour permettre les routes d'upload (qui rejetteront)
		uploadConfig.ClamAVEnabled = false
		uploadValidator, _ = services.NewUploadValidator(uploadConfig, r.logger)
	}
	auditService := services.NewAuditService(r.db, r.logger)
	trackUploadService := services.NewTrackUploadService(r.db.GormDB, r.logger)

	// Handlers
	sessionHandler := handlers.NewSessionHandler(sessionService, auditService, r.logger)
	uploadHandler := handlers.NewUploadHandler(uploadValidator, auditService, trackUploadService, r.logger, r.config.MaxConcurrentUploads)
	auditHandler := handlers.NewAuditHandler(auditService, r.logger)

	// Routes de session
	sessions := protected.Group("/sessions")
	{
		sessions.POST("/logout", sessionHandler.Logout())
		sessions.POST("/logout-all", sessionHandler.LogoutAll())
		// ISSUE-007: Ajouter route sans trailing slash pour éviter redirection 301
		sessions.GET("", sessionHandler.GetSessions())
		sessions.GET("/", sessionHandler.GetSessions()) // Garder aussi avec slash pour compatibilité
		sessions.DELETE("/:session_id", sessionHandler.RevokeSession())
		sessions.GET("/stats", sessionHandler.GetSessionStats())
		sessions.POST("/refresh", sessionHandler.RefreshSession())
	}

	// Routes d'upload avec rate limiting spécifique
	uploads := protected.Group("/uploads")
	{
		if r.config.RedisClient != nil {
			uploads.Use(middleware.UploadRateLimit(r.config.RedisClient))
		}
		uploads.POST("/", uploadHandler.UploadFile())
		uploads.POST("/batch", uploadHandler.BatchUpload())
		uploads.GET("/:id/status", uploadHandler.GetUploadStatus())
		uploads.GET("/:id/progress", uploadHandler.UploadProgress())
		uploads.DELETE("/:id", uploadHandler.DeleteUpload())
		uploads.GET("/stats", uploadHandler.GetUploadStats())
	}

	// Routes d'audit
	audit := protected.Group("/audit")
	{
		audit.GET("/logs", auditHandler.SearchLogs())
		audit.GET("/stats", auditHandler.GetStats())
		audit.GET("/activity", auditHandler.GetUserActivity())
		audit.GET("/suspicious", auditHandler.DetectSuspiciousActivity())
		audit.GET("/ip/:ip", auditHandler.GetIPActivity())
		audit.GET("/logs/:id", auditHandler.GetAuditLog())
		audit.POST("/cleanup", auditHandler.CleanupOldLogs())
	}

	// Action 2.1.1.2: Dashboard aggregation endpoint
	// Create track service wrapper for dashboard handler (to avoid import cycle)
	uploadDir := r.config.UploadDir
	if uploadDir == "" {
		uploadDir = "uploads/tracks"
	}
	trackServiceForDashboard := trackcore.NewTrackService(r.db.GormDB, r.logger, uploadDir)
	if r.config.CacheService != nil {
		trackServiceForDashboard.SetCacheService(r.config.CacheService)
	}

	// Create wrapper function that adapts trackcore.TrackListParams to handlers.TrackListParamsForDashboard
	trackListFunc := func(ctx context.Context, params handlers.TrackListParamsForDashboard) ([]*models.Track, int64, error) {
		return trackServiceForDashboard.ListTracks(ctx, trackcore.TrackListParams{
			Page:      params.Page,
			Limit:     params.Limit,
			UserID:    params.UserID,
			Genre:     params.Genre,
			Format:    params.Format,
			SortBy:    params.SortBy,
			SortOrder: params.SortOrder,
		})
	}

	dashboardHandler := handlers.NewDashboardHandler(auditService, trackListFunc, r.logger)
	protected.GET("/dashboard", dashboardHandler.GetDashboard())

	// Routes de conversations (chat rooms)
	roomRepo := repositories.NewRoomRepository(r.db.GormDB)
	messageRepo := repositories.NewChatMessageRepository(r.db.GormDB)       // New
	roomService := services.NewRoomService(roomRepo, messageRepo, r.logger) // Updated constructor
	roomHandler := handlers.NewRoomHandler(roomService, r.logger)

	conversations := protected.Group("/conversations")
	{
		conversations.GET("", roomHandler.GetUserRooms)
		conversations.POST("", roomHandler.CreateRoom)
		conversations.GET("/:id", roomHandler.GetRoom)
		conversations.PUT("/:id", roomHandler.UpdateRoom)    // BE-API-012: Update conversation endpoint
		conversations.DELETE("/:id", roomHandler.DeleteRoom) // BE-API-010: Delete conversation endpoint
		conversations.POST("/:id/members", roomHandler.AddMember)
		conversations.POST("/:id/participants", roomHandler.AddParticipant)              // BE-API-011: Add participant endpoint
		conversations.DELETE("/:id/participants/:userId", roomHandler.RemoveParticipant) // BE-API-011: Remove participant endpoint
		conversations.GET("/:id/history", roomHandler.GetRoomHistory)
	}

	// BE-API-016: Setup notification routes
	notificationService := services.NewNotificationService(r.db, r.logger)
	handlers.NewNotificationHandlers(notificationService)
	notifications := protected.Group("/notifications")
	{
		notifications.GET("", handlers.NotificationHandlersInstance.GetNotifications)            // BE-API-016: Get notifications endpoint
		notifications.GET("/unread-count", handlers.NotificationHandlersInstance.GetUnreadCount) // BE-API-016: Get unread count endpoint
		notifications.POST("/:id/read", handlers.NotificationHandlersInstance.MarkAsRead)        // BE-API-016: Mark notification as read endpoint
		notifications.POST("/read-all", handlers.NotificationHandlersInstance.MarkAllAsRead)     // BE-API-016: Mark all notifications as read endpoint
		notifications.DELETE("/:id", handlers.NotificationHandlersInstance.DeleteNotification)   // BE-API-016: Delete notification endpoint
		notifications.DELETE("", handlers.NotificationHandlersInstance.DeleteAllNotifications)   // BE-API-016: Delete all notifications endpoint
	}

	// Routes administrateur (avec authentification + permissions admin)
	admin := v1.Group("/admin")
	{
		if r.config.AuthMiddleware != nil {
			admin.Use(r.config.AuthMiddleware.RequireAuth())
			admin.Use(r.config.AuthMiddleware.RequireAdmin())
		}

		// Audit logs (disponibles)
		admin.GET("/audit/logs", auditHandler.SearchLogs())
		admin.GET("/audit/stats", auditHandler.GetStats())
		admin.GET("/audit/suspicious", auditHandler.DetectSuspiciousActivity())

		// MOD-P2-006: Profiling pprof (protégé par auth admin)
		admin.Any("/debug/pprof/*path", gin.WrapH(http.DefaultServeMux))
	}
}

// setupSocialRoutes configure les routes sociales
func (r *APIRouter) setupSocialRoutes(router *gin.RouterGroup) {
	socialService := socialcore.NewService(r.db.GormDB, r.logger)
	socialHandler := handlers.NewSocialHandler(socialService, r.logger)

	social := router.Group("/social")
	{
		// Public routes
		social.GET("/feed", socialHandler.GetFeed)
		social.GET("/posts/user/:user_id", socialHandler.GetPostsByUser)

		// Protected routes
		if r.config.AuthMiddleware != nil {
			protected := social.Group("")
			protected.Use(r.config.AuthMiddleware.RequireAuth())
			// BE-SEC-004: Apply CSRF protection to all state-changing endpoints
			r.applyCSRFProtection(protected)

			protected.POST("/posts", socialHandler.CreatePost)
			protected.POST("/like", socialHandler.ToggleLike)
			protected.POST("/comments", socialHandler.AddComment)
		}
	}
}
