package routes

import (
	"fotbal-club/internal/config"
	"fotbal-club/internal/controllers"
	"fotbal-club/internal/middleware"
	"fotbal-club/internal/services"
	"fotbal-club/pkg/email"
	"time"

	"github.com/gin-gonic/gin"
	"gorm.io/gorm"
)

// Global newsletter automation instance
var newsletterAutomation *services.NewsletterAutomation

// SetNewsletterAutomation stores the newsletter automation instance
func SetNewsletterAutomation(na *services.NewsletterAutomation) {
	newsletterAutomation = na
}

// GetNewsletterAutomation returns the newsletter automation instance
func GetNewsletterAutomation() *services.NewsletterAutomation {
	return newsletterAutomation
}

// SetupRoutes configures all the routes for the application
func SetupRoutes(api *gin.RouterGroup, db *gorm.DB) {
	emailService := email.NewEmailService(config.AppConfig, db)

	// Initialize controllers
	baseController := &controllers.BaseController{DB: db}
	authController := controllers.NewAuthController(db)
	facrController := controllers.NewFACRController(db)
	contactController := controllers.NewContactController(db, emailService)
	passwordController := controllers.NewPasswordController(db, emailService)
	aiController := controllers.NewAIController(db)
	scoreboardController := controllers.NewScoreboardController(db)
	youtubeController := controllers.NewYouTubeController(db)
	aboutController := controllers.NewAboutController(db)
	galleryController := controllers.NewGalleryController(db)
	umamiController := controllers.NewUmamiController()
	filesController := &controllers.FilesController{DB: db}
	notificationsController := controllers.NewNotificationsController(db, emailService)
	emailController := controllers.NewEmailController(db)
	prefetchController := controllers.NewPrefetchController()
	seoController := controllers.NewSEOController(db)
	navigationController := controllers.NewNavigationController(db)
	pollController := controllers.NewPollController(db)
	clothingController := controllers.NewClothingController(db)
	pageElementConfigController := controllers.NewPageElementConfigController(db)
	imageProcessingController := &controllers.ImageProcessingController{}
	articleController := controllers.NewArticleController(db)
	myuibrixController := &controllers.MyUIbrixController{DB: db}

	// API v1 group
	{
		// Health check
		api.GET("/health", baseController.HealthCheck)

		// Image proxy (public) to work around CORS when reading images in Canvas on the frontend
		api.GET("/proxy/image", baseController.ProxyImage)

		// Public SEO: metadata
		api.GET("/seo", seoController.GetPublicSEO)

		// Public navigation endpoints
		api.GET("/navigation", navigationController.GetNavigationItems)
		api.GET("/social-links", navigationController.GetSocialLinks)

		// Public page element configurations
		api.GET("/page-elements", pageElementConfigController.GetPageElementConfigs)

		// Email tracking (public)
		api.GET("/email/open.gif", emailController.OpenPixel)
		api.GET("/email/click", emailController.ClickRedirect)
		api.GET("/email/spam", emailController.MarkSpam)
		api.GET("/email/unsubscribe", emailController.Unsubscribe)

		// Initial setup (public)
		api.GET("/setup/status", baseController.SetupStatus)
		api.POST("/setup/initialize", baseController.SetupInitialize)
		// SMTP validation (public during setup; does not send email, only connects)
		api.POST("/setup/validate-smtp", baseController.ValidateSMTP)

		// Auth routes
		auth := api.Group("/auth")
		{
			// Limit login attempts to mitigate brute force
			auth.POST("/login", middleware.RateLimit(15, time.Minute), authController.Login)
			// Logout clears auth cookie (stateless)
			auth.POST("/logout", authController.Logout)
			// Limit registration bursts
			auth.POST("/register", middleware.RateLimit(5, time.Hour), authController.Register)
			auth.GET("/check-email", authController.CheckEmail)
			// Password reset (public)
			auth.POST("/initiate-password-reset", passwordController.InitiatePasswordReset)
			auth.POST("/verify-reset-code", passwordController.VerifyResetCode)
			auth.POST("/complete-password-reset", passwordController.CompletePasswordReset)
			// Legacy password reset endpoints (deprecated)
			auth.POST("/forgot-password", passwordController.ForgotPassword)
			auth.POST("/forgot-password-admin", passwordController.AdminSendReset)
			auth.POST("/reset-password", passwordController.ResetPassword)
			auth.GET("/me", middleware.JWTAuth(db), authController.GetCurrentUser)
			// Initial admin setup helpers
			auth.GET("/admin/exists", authController.AdminExists)
			auth.POST("/make-admin", middleware.JWTAuth(db), authController.MakeAdmin)
		}

		// Event routes (public)
		eventController := &controllers.EventController{DB: db}
		events := api.Group("/events")
		{
			events.GET("", eventController.GetEvents)
			events.GET("/upcoming", eventController.GetUpcomingEvents)
			events.GET("/:id", eventController.GetEventByID)
		}

		// Protected routes (require authentication)
		protected := api.Group("")
		protected.Use(middleware.JWTAuth(db))
		{
			// AI endpoints (protected)
			ai := protected.Group("/ai")
			{
				ai.POST("/blog/generate", aiController.GenerateBlog)
				ai.POST("/about/generate", aiController.GenerateAboutPage)
			}

			// User profile
			protected.GET("/me", authController.GetCurrentUser)

			// Uploads are registered as a public endpoint below so the handler can
			// allow unauthenticated uploads during initial setup (when no admin exists).
			// The protected group remains for other authenticated endpoints.

			// Events (protected)
			protectedEvents := protected.Group("/events")
			{
				protectedEvents.POST("", eventController.CreateEvent)
				protectedEvents.PUT("/:id", eventController.UpdateEvent)
				protectedEvents.DELETE("/:id", eventController.DeleteEvent)
			}

			// Articles (protected - accessible by editors and admins)
			articles := protected.Group("/articles")
			{
				articles.POST("", articleController.CreateArticle)
				articles.PUT("/:id", baseController.UpdateArticle)
				articles.DELETE("/:id", baseController.DeleteArticle)
				// Link article to FACR match
				articles.POST("/:id/match-link", baseController.PutArticleMatchLink)
				articles.DELETE("/:id/match-link", baseController.DeleteArticleMatchLink)
			}

			// Teams (protected)
			teams := protected.Group("/teams")
			{
				teams.POST("", baseController.CreateTeam)
				teams.PUT("/:id", baseController.UpdateTeam)
				teams.DELETE("/:id", baseController.DeleteTeam)
			}

			// Players (protected)
			players := protected.Group("/players")
			{
				players.POST("", baseController.CreatePlayer)
				players.PUT("/:id", baseController.UpdatePlayer)
				players.DELETE("/:id", baseController.DeletePlayer)
			}

			// Sponsors (protected CRUD)
			sponsors := protected.Group("/sponsors")
			{
				sponsors.POST("", baseController.CreateSponsor)
				sponsors.PUT("/:id", baseController.UpdateSponsor)
				sponsors.DELETE("/:id", baseController.DeleteSponsor)
			}

			// Admin routes (single consolidated group)
			admin := protected.Group("/admin")
			admin.Use(middleware.RoleAuth("admin"))
			{
				// Admin-only endpoints for managing sponsors, etc. (user CRUD removed; no handlers defined)

				// Competition aliases (admin)
				admin.GET("/competition-aliases", baseController.GetCompetitionAliases)
				admin.PUT("/competition-aliases/:code", baseController.PutCompetitionAlias)
				admin.DELETE("/competition-aliases/:code", baseController.DeleteCompetitionAlias)
				admin.POST("/competition-aliases/reorder", baseController.ReorderCompetitionAliases)

				// Categories (admin)
				admin.POST("/categories", baseController.CreateCategory)
				admin.PUT("/categories/:id", baseController.UpdateCategory)
				admin.DELETE("/categories/:id", baseController.DeleteCategory)

				// Settings (singleton)
				admin.GET("/settings", baseController.GetSettings)
				admin.PUT("/settings", baseController.UpdateSettings)

				// About page (singleton)
				admin.GET("/about", aboutController.GetAdminAboutPage)
				admin.PUT("/about", aboutController.UpsertAboutPage)
				admin.DELETE("/about", aboutController.DeleteAboutPage)

				// Scoreboard (singleton)
				admin.GET("/scoreboard", scoreboardController.GetAdmin)
				admin.PUT("/scoreboard", scoreboardController.PutAdmin)
				// Scoreboard timer controls
				admin.POST("/scoreboard/timer/start", scoreboardController.StartTimer)
				admin.POST("/scoreboard/timer/pause", scoreboardController.PauseTimer)
				admin.POST("/scoreboard/timer/reset", scoreboardController.ResetTimer)
				// Scoreboard advanced actions
				admin.POST("/scoreboard/swap-sides", scoreboardController.SwapSides)
				admin.POST("/scoreboard/second-half", scoreboardController.StartSecondHalf)
				// Presets: save/list/load
				admin.POST("/scoreboard/save", scoreboardController.SaveState)
				admin.GET("/scoreboard/saves", scoreboardController.ListSaves)
				admin.POST("/scoreboard/load", scoreboardController.LoadSaved)
				// Scoreboard sponsors & QR (admin-only)
				admin.GET("/scoreboard/sponsors", scoreboardController.ListSponsors)
				admin.POST("/scoreboard/sponsors/upload", scoreboardController.UploadSponsors)
				admin.DELETE("/scoreboard/sponsors", scoreboardController.DeleteSponsor)
				admin.GET("/scoreboard/qr", scoreboardController.GetQR)
				admin.POST("/scoreboard/qr", scoreboardController.UploadQR)

				// Users (admin)
				admin.GET("/users", authController.ListUsers)
				// Create/Update/Delete users
				admin.POST("/users", authController.AdminCreateUser)
				admin.PUT("/users/:id", authController.AdminUpdateUser)
				admin.DELETE("/users/:id", authController.AdminDeleteUser)
				// Admin: send password reset email using special SMTP override
				admin.POST("/users/send-reset", passwordController.AdminSendReset)
				// Admin: reset password for a specific user ID
				admin.POST("/users/:id/reset-password", passwordController.AdminSendResetByID)

				// Admin matches merged with overrides
				admin.GET("/matches", baseController.GetAdminMatches)

				// Match & Team Logo Overrides
				overrides := admin.Group("")
				{
					// Match overrides
					overrides.GET("/match-overrides", baseController.GetMatchOverrides)
					overrides.PUT("/match-overrides/:external_match_id", baseController.PutMatchOverride)
					overrides.PATCH("/match-overrides/:external_match_id", baseController.PatchMatchOverride)

					// Team logo overrides
					overrides.GET("/team-logo-overrides", baseController.GetTeamLogoOverrides)
					overrides.PUT("/team-logo-overrides/:external_team_id", baseController.PutTeamLogoOverride)
					overrides.PATCH("/team-logo-overrides/:external_team_id", baseController.PatchTeamLogoOverride)
				}

				// Contact messages management
				contactMessages := admin.Group("/contact-messages")
				{
					contactMessages.GET("", contactController.GetContactMessages)
					contactMessages.GET("/:id", contactController.GetContactMessage)
					contactMessages.PATCH("/:id/read", contactController.MarkMessageAsRead)
					contactMessages.POST("/:id/forward", contactController.ForwardContactMessage)
					contactMessages.POST("/forward-all", contactController.ForwardAllContactMessages)
					contactMessages.DELETE("/:id", contactController.DeleteContactMessage)
					contactMessages.DELETE("", contactController.DeleteContactMessages) // Bulk delete
				}

				// Newsletter management
				admin.GET("/newsletter/subscribers", contactController.GetNewsletterSubscribers)
				admin.POST("/newsletter/send", contactController.SendNewsletter)
				admin.POST("/newsletter/preview", contactController.PreviewNewsletter)
				admin.POST("/newsletter/test", contactController.SendNewsletterTest)
				// New: send prebuilt digest by type and toggle automation
				admin.POST("/newsletter/send-digest", contactController.SendNewsletterDigest)
				admin.PATCH("/newsletter/enable", contactController.UpdateNewsletterAutomation)
				// Removed deprecated SMTP test route (use /newsletter/test instead)
				admin.GET("/newsletter/status", contactController.GetNewsletterStatus)
				admin.GET("/newsletter/stats/recent", emailController.GetRecentEmailStats)
				admin.GET("/newsletter/stats/:id/events", emailController.GetEmailEventsForLog)
				admin.PATCH("/newsletter/subscribers/:id/preferences", contactController.UpdateNewsletterSubscriberPreferences)
				admin.DELETE("/newsletter/subscribers/:id", contactController.DeleteNewsletterSubscriber)
				admin.PATCH("/newsletter/subscribers/:id/status", contactController.UpdateNewsletterSubscriberStatus)

				// Notifications (admin)
				notifications := admin.Group("/notifications")
				{
					notifications.POST("/competition", notificationsController.SendCompetitionNotification)
					notifications.POST("/match", notificationsController.SendMatchNotification)
				}

				// Prefetch management (admin)
				prefetch := admin.Group("/prefetch")
				{
					prefetch.GET("/status", prefetchController.Status)
					prefetch.POST("/trigger", prefetchController.Trigger)
				}

				// Cache RAW viewer (admin)
				cache := admin.Group("/cache")
				{
					cache.GET("/list", baseController.GetAdminCacheList)
					cache.GET("/file", baseController.GetAdminCacheFile)
				}

				// Gallery management (admin)
				gallery := admin.Group("/gallery")
				{
					gallery.GET("/profile", galleryController.GetGalleryProfile)     // Get Zonerama profile
					gallery.POST("/albums/fetch", galleryController.FetchAlbum)       // Fetch single album
					gallery.DELETE("/albums/:id", galleryController.DeleteAlbum)      // Delete album
					gallery.POST("/refresh", galleryController.RefreshFromZonerama)   // Refresh from Zonerama
				}

				// Alias endpoint for saving a single Zonerama album (keeps older frontend code working)
				admin.POST("/zonerama/save-album", galleryController.FetchAlbum)
				// Save or update a chosen Zonerama pick (photo) in unified cache
				admin.POST("/zonerama/pick", baseController.PutZoneramaPick)

				// SEO admin
				admin.GET("/seo", seoController.GetSEOSettings)
				admin.PUT("/seo", seoController.UpdateSEOSettings)

				// Files management (admin)
				files := admin.Group("/files")
				{
					files.GET("", filesController.GetAllFiles)
					files.GET("/unused", filesController.GetUnusedFiles)
					files.GET("/duplicates", filesController.GetDuplicateFiles)
					files.GET("/:id/usages", filesController.GetFileUsages)
					files.DELETE("/:id", filesController.DeleteFile)
					files.POST("/scan", filesController.ScanAndSyncFiles)
					files.POST("/refresh-tracking", filesController.RefreshFileTracking)
				}

				// Navigation management (admin)
				navigation := admin.Group("/navigation")
				{
					navigation.GET("", navigationController.GetAllNavigationItems)
					navigation.POST("", navigationController.CreateNavigationItem)
					navigation.PUT("/:id", navigationController.UpdateNavigationItem)
					navigation.DELETE("/:id", navigationController.DeleteNavigationItem)
					navigation.POST("/reorder", navigationController.ReorderNavigationItems)
					navigation.POST("/seed", navigationController.SeedDefaultNavigation)
				}

				// Social links management (admin)
				socialLinks := admin.Group("/social-links")
				{
					socialLinks.GET("", navigationController.GetAllSocialLinks)
					socialLinks.POST("", navigationController.CreateSocialLink)
					socialLinks.PUT("/:id", navigationController.UpdateSocialLink)
					socialLinks.DELETE("/:id", navigationController.DeleteSocialLink)
					socialLinks.POST("/reorder", navigationController.ReorderSocialLinks)
				}

				// Clothing management (admin)
				clothing := admin.Group("/clothing")
				{
					clothing.GET("", clothingController.GetClothingAdmin)
					clothing.GET("/:id", clothingController.GetClothingByID)
					clothing.POST("", clothingController.CreateClothing)
					clothing.PUT("/:id", clothingController.UpdateClothing)
					clothing.DELETE("/:id", clothingController.DeleteClothing)
					clothing.POST("/reorder", clothingController.UpdateClothingOrder)
				}

				// Polls management (admin)
				polls := admin.Group("/polls")
				{
					polls.GET("", pollController.GetPolls)
					polls.GET("/:id", pollController.GetPoll)
					polls.POST("", pollController.CreatePoll)
					polls.PUT("/:id", pollController.UpdatePoll)
					polls.DELETE("/:id", pollController.DeletePoll)
					polls.GET("/:id/stats", pollController.GetPollStats)
				}

				// Page element configurations management (admin)
				pageElements := admin.Group("/page-elements")
				{
					pageElements.GET("", pageElementConfigController.GetAllPageElementConfigs)
					pageElements.POST("", pageElementConfigController.CreateOrUpdatePageElementConfig)
					pageElements.PUT("/:id", pageElementConfigController.UpdatePageElementConfig)
					pageElements.DELETE("/:id", pageElementConfigController.DeletePageElementConfig)
					pageElements.POST("/batch", pageElementConfigController.BatchUpdatePageElementConfigs)
				}

				// MyUIbrix optimization and validation endpoints (admin)
				myuibrix := admin.Group("/myuibrix")
				{
					myuibrix.POST("/validate", myuibrixController.ValidateElementConfig)
					myuibrix.POST("/validate-batch", myuibrixController.BatchValidateConfigs)
					myuibrix.GET("/preview", myuibrixController.GetElementPreview)
					myuibrix.GET("/optimize-layout", myuibrixController.OptimizePageLayout)
				}
			}
		}

		// Register analytics routes (public tracking + admin endpoints)
		RegisterAnalyticsRoutes(api, db)
		
		// Umami analytics routes
		api.GET("/umami/config", umamiController.GetUmamiConfig)
		// Public setup endpoint (no auth required - called during initial setup)
		api.POST("/umami/initialize-setup", umamiController.InitializeUmamiSetup)
		
		umami := api.Group("/admin/umami")
		umami.Use(middleware.JWTAuth(db))
		umami.Use(middleware.RoleAuth("admin"))
		{
			umami.POST("/initialize", umamiController.InitializeUmami)
			umami.GET("/stats", umamiController.GetStats)
			umami.GET("/metrics/:type", umamiController.GetMetrics)
			umami.GET("/pageviews", umamiController.GetPageviews)
		}

		// Register contact info routes (public + admin endpoints)
		RegisterContactInfoRoutes(api, db)

		// Public API routes
		// Allow uploads publicly so initial setup can upload a club logo before an admin exists.
		api.POST("/upload", middleware.RateLimit(30, time.Minute), baseController.UploadImage)
		
		// Image processing endpoints (protected)
		imageProcessing := protected.Group("/image-processing")
		{
			imageProcessing.POST("/process", imageProcessingController.ProcessImage)
			imageProcessing.POST("/crop-upload", imageProcessingController.CropAndUpload)
			imageProcessing.POST("/quick-edit", imageProcessingController.QuickEdit)
		}

		// Public scoreboard
		api.GET("/scoreboard", scoreboardController.GetPublic)
		api.GET("/scoreboard/colors/derive", scoreboardController.DeriveColors)

		// Public core endpoints
		api.GET("/settings", baseController.GetPublicSettings)
		api.GET("/competition-aliases", baseController.GetPublicCompetitionAliases)
		api.GET("/public/team-logo-overrides", baseController.GetPublicTeamLogoOverrides)

		// Articles (public)
		api.GET("/articles/featured", baseController.GetFeaturedArticles)
		api.GET("/articles", baseController.GetArticles)
		api.GET("/articles/:id", baseController.GetArticle)
		api.GET("/articles/slug/:slug", baseController.GetArticleBySlug)
		api.POST("/articles/:id/read", baseController.IncrementArticleRead)
		api.POST("/articles/:id/track-view", baseController.TrackArticleView)
		// Public read-only access to article-match link
		api.GET("/articles/:id/match-link", baseController.GetArticleMatchLink)
		// Public categories
		api.GET("/categories", baseController.GetCategories)
		// Public YouTube cached videos
		api.GET("/youtube/videos", youtubeController.GetYouTubeVideos)
		// Public About page
		api.GET("/about", aboutController.GetPublicAboutPage)
		api.GET("/teams", baseController.GetTeams)
		api.GET("/teams/:id", baseController.GetTeam)
		api.GET("/players", baseController.GetPlayers)
		api.GET("/players/:id", baseController.GetPlayer)
		api.GET("/sponsors", baseController.GetSponsors)
		api.GET("/matches", baseController.GetMatches)
		api.GET("/matches/history", baseController.GetMatchesHistory)
		api.GET("/standings", baseController.GetStandings)

		// Gallery (public): albums and photos
		api.GET("/gallery/albums", galleryController.GetGalleryAlbums)      // Get all albums
		api.GET("/gallery/albums/:id", galleryController.GetGalleryAlbum)   // Get single album with photos
		api.GET("/gallery/proxy-image", galleryController.ProxyImage)       // Proxy Zonerama images to avoid CORS

		// Legacy Zonerama endpoints (keep for backwards compatibility)
		api.GET("/zonerama/album", baseController.GetZoneramaAlbum)
		// Alias to support hyphenated path used by some frontend calls
		api.GET("/zonerama-album", baseController.GetZoneramaAlbum)
		api.GET("/zonerama/picks", baseController.GetZoneramaPicks)

		// Clothing (public) - active items only
		api.GET("/clothing", clothingController.GetClothing)

		// Polls (public)
		api.GET("/polls", pollController.GetPolls)
		api.GET("/polls/:id", pollController.GetPoll)
		api.POST("/polls/:id/vote", middleware.RateLimit(10, time.Minute), pollController.Vote)
		api.GET("/polls/:id/results", pollController.GetPollResults)

		// Contact form and newsletter endpoints (public) – rate limited to prevent abuse
		api.POST("/contact", middleware.RateLimit(10, time.Minute), contactController.SubmitContactForm)
		api.POST("/newsletter/subscribe", middleware.RateLimit(30, time.Minute), contactController.SubscribeToNewsletter)
		api.POST("/newsletter/setup", middleware.RateLimit(30, time.Minute), contactController.SetupNewsletterPreferences)
		api.POST("/newsletter/unsubscribe/:email", middleware.RateLimit(30, time.Minute), contactController.UnsubscribeFromNewsletter)
		// Token-based management (no auth)
		api.GET("/newsletter/preferences", contactController.GetNewsletterPreferencesByToken)
		api.POST("/newsletter/preferences", contactController.SaveNewsletterPreferencesByToken)
		api.POST("/newsletter/unsubscribe-token", contactController.UnsubscribeByToken)

	}
	// FACR scraper endpoints (integrated): /api/v1/facr/*
	facr := api.Group("/facr")
	{
		facr.GET("/club/search", facrController.SearchClubs)
		facr.GET("/club/:type/:id", facrController.GetClubInfo)
		facr.GET("/club/:type/:id/table", facrController.GetClubTables)
	}
}

// SetupRootRoutes registers endpoints at the root (no /api prefix)
func SetupRootRoutes(r *gin.Engine, db *gorm.DB) {
	seoController := controllers.NewSEOController(db)
	r.GET("/robots.txt", seoController.GetRobotsTXT)
	r.GET("/sitemap.xml", seoController.GetSitemapXML)
}
