package api

import (
	"context"
	"os"

	"github.com/gin-gonic/gin"
	"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/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"

	"veza-backend-api/internal/core/marketplace"
	"veza-backend-api/internal/services"
	authcore "veza-backend-api/internal/core/auth"
	trackcore "veza-backend-api/internal/core/track"
	"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
}

// NewAPIRouter crée une nouvelle instance de APIRouter
func NewAPIRouter(db *database.Database, cfg *config.Config) *APIRouter {
	return &APIRouter{
		db:     db,
		config: cfg,
		logger: zap.L(),
	}
}

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

	// 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.Recovery(r.logger))
	// SECURITY: CORS configuration - use config.CORSOrigins strictly (P0-SECURITY)
	// No fallback to CORSDefault() to avoid wildcard in production
	if r.config != nil && len(r.config.CORSOrigins) > 0 {
		router.Use(middleware.CORS(r.config.CORSOrigins))
	} else {
		// If CORSOrigins is empty, log warning but don't use wildcard
		// This should have been caught by ValidateForEnvironment() in production
		r.logger.Warn("CORS origins not configured - CORS middleware not applied. This may cause CORS errors in browsers.")
	}
	router.Use(middleware.RequestID())
	// Rate limiting via config.RateLimiter si disponible, sinon utiliser SimpleRateLimiter
	if r.config != nil && r.config.RateLimiter != nil {
		router.Use(r.config.RateLimiter.RateLimitMiddleware())
	} else if r.config != nil && r.config.SimpleRateLimiter != nil {
		router.Use(r.config.SimpleRateLimiter.Middleware())
	}

	// Swagger Documentation
	router.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))

	// Routes core publiques (health, metrics, upload info)
	r.setupCorePublicRoutes(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)

		r.setupAuthRoutes(v1)

		// Réactivation des routes User et Track pour Phase 1
		r.setupUserRoutes(v1)
		r.setupTrackRoutes(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)
	}
}

// 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())
		
		// GO-012: Create product requires creator/premium/admin role
		createGroup := protected.Group("")
		createGroup.Use(r.config.AuthMiddleware.RequireContentCreatorRole())
		createGroup.POST("/products", marketHandler.CreateProduct)
		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) {
	// 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 := services.NewJWTService(r.config.JWTSecret)
	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,
	)

	// 3. Handlers
	authGroup := router.Group("/auth")
	{
		authGroup.POST("/register", handlers.Register(authService, r.logger))
		authGroup.POST("/login", handlers.Login(authService, sessionService, r.logger))
		authGroup.POST("/refresh", handlers.Refresh(authService, r.logger))
		authGroup.POST("/verify-email", handlers.VerifyEmail(authService))
		authGroup.POST("/resend-verification", handlers.ResendVerification(authService, r.logger))
		authGroup.GET("/check-username", handlers.CheckUsername(authService))

		// Password reset routes (public)
		passwordGroup := authGroup.Group("/password")
		{
			passwordGroup.POST("/reset-request", handlers.RequestPasswordReset(
				passwordResetService,
				passwordService,
				emailService,
				r.logger,
			))
			passwordGroup.POST("/reset", handlers.ResetPassword(
				passwordResetService,
				passwordService,
				authService,
				sessionService,
				r.logger,
			))
		}

		// Protected routes (authentification JWT requise)
		protected := authGroup.Group("")
		protected.Use(r.config.AuthMiddleware.RequireAuth()) // Changed to RequireAuth()
		{
			protected.POST("/logout", handlers.Logout(authService, sessionService, r.logger))
			protected.GET("/me", handlers.GetMe())
		}
	}
}
// 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)

	users := router.Group("/users")
	{
		users.GET("/:id", profileHandler.GetProfile)
		users.GET("/by-username/:username", profileHandler.GetProfileByUsername)

		// Protected routes
		if r.config.AuthMiddleware != nil {
			protected := users.Group("")
			protected.Use(r.config.AuthMiddleware.RequireAuth())
			protected.PUT("/:id", profileHandler.UpdateProfile)
			protected.GET("/:id/completion", profileHandler.GetProfileCompletion)
		}
	}
}

// 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)
	trackUploadService := services.NewTrackUploadService(r.db.GormDB, r.logger)
	chunkService := services.NewTrackChunkService(chunksDir, 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,
	)

	tracks := router.Group("/tracks")
	{
		// Public routes
		tracks.GET("", trackHandler.ListTracks)
		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())

			// GO-012: Upload track requires creator/premium/admin role
			uploadGroup := protected.Group("")
			uploadGroup.Use(r.config.AuthMiddleware.RequireContentCreatorRole())
			uploadGroup.POST("", trackHandler.UploadTrack)
			protected.PUT("/:id", trackHandler.UpdateTrack)
			protected.DELETE("/:id", 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)
		}
	}

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

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

	users := router.Group("/users")
	{
		users.GET("/:id/likes", trackHandler.GetUserLikedTracks)
	}
}

// setupChatRoutes configure les routes de chat
func (r *APIRouter) setupChatRoutes(router *gin.RouterGroup) {
	chatService := services.NewChatService(r.config.ChatJWTSecret, 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())
			chat.POST("/token", chatHandler.GetToken)
		}
	}
}

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

	playlistHandler := handlers.NewPlaylistHandler(playlistService, r.db.GormDB, r.logger)

	// Protected routes for playlists
	playlists := router.Group("/playlists")
	if r.config.AuthMiddleware != nil {
		playlists.Use(r.config.AuthMiddleware.RequireAuth())
		{
			playlists.GET("", playlistHandler.GetPlaylists)
			playlists.POST("", playlistHandler.CreatePlaylist)
			playlists.GET("/:id", playlistHandler.GetPlaylist)
			playlists.PUT("/:id", playlistHandler.UpdatePlaylist)
			playlists.DELETE("/:id", 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)
		}
	}
}

// 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())
	}
	{
		webhooks.POST("", webhookHandler.RegisterWebhook())
		webhooks.GET("", webhookHandler.ListWebhooks())
		webhooks.DELETE("/:id", webhookHandler.DeleteWebhook())
		webhooks.GET("/stats", webhookHandler.GetWebhookStats())
		webhooks.POST("/:id/test", webhookHandler.TestWebhook())
	}
}

// setupCorePublicRoutes configure les routes publiques core (health, metrics, upload info)
func (r *APIRouter) setupCorePublicRoutes(router *gin.Engine) {
	// Middleware for deprecated routes
	deprecated := router.Group("/")
	deprecated.Use(middleware.DeprecationWarning(r.logger))

	// 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
		}
		healthHandler := handlers.NewHealthHandler(r.db.GormDB, r.logger, redisClient, rabbitMQEventBus)
		healthCheckHandler = healthHandler.Check
		livenessHandler = healthHandler.Liveness
		readinessHandler = healthHandler.Readiness
	} else {
		healthCheckHandler = handlers.SimpleHealthCheck
		livenessHandler = handlers.SimpleHealthCheck
		readinessHandler = handlers.SimpleHealthCheck
	}

	// Deprecated Public Core Routes
	deprecated.GET("/health", healthCheckHandler)
	deprecated.GET("/healthz", livenessHandler)
	deprecated.GET("/readyz", readinessHandler)
	deprecated.GET("/metrics", handlers.PrometheusMetrics())
	if r.config != nil && r.config.ErrorMetrics != nil {
		deprecated.GET("/metrics/aggregated", handlers.AggregatedMetrics(r.config.ErrorMetrics))
	}
	deprecated.GET("/system/metrics", 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)
		if r.db != nil && r.db.GormDB != nil {
			uploadConfig := services.DefaultUploadConfig()
			uploadValidator, err := services.NewUploadValidator(uploadConfig, r.logger)
			if err == nil {
				auditService := services.NewAuditService(r.db, r.logger)
				uploadHandler := handlers.NewUploadHandler(uploadValidator, auditService, r.logger)
				v1Public.GET("/upload/limits", uploadHandler.GetUploadLimits())
				v1Public.GET("/upload/validate-type", uploadHandler.ValidateFileType())
			}
		}
	}
}

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

	// 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)
	uploadConfig := services.DefaultUploadConfig()
	uploadValidator, err := services.NewUploadValidator(uploadConfig, r.logger)
	if err != nil {
		r.logger.Error("Failed to create upload validator", zap.Error(err))
		return
	}
	auditService := services.NewAuditService(r.db, r.logger)

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

	// Routes de session
	sessions := protected.Group("/sessions")
	{
		sessions.POST("/logout", sessionHandler.Logout())
		sessions.POST("/logout-all", sessionHandler.LogoutAll())
		sessions.GET("/", sessionHandler.GetSessions())
		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())
	}

	// 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.POST("/:id/members", roomHandler.AddMember)
		conversations.GET("/:id/history", roomHandler.GetRoomHistory)
	}

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