package admin

import (
	"net/http"
	"net/http/httputil"
	"net/url"
	"os"
	"strings"

	"github.com/labstack/echo/v4"
	"gorm.io/gorm"

	"github.com/treytartt/honeydue-api/internal/admin/handlers"
	"github.com/treytartt/honeydue-api/internal/config"
	"github.com/treytartt/honeydue-api/internal/middleware"
	"github.com/treytartt/honeydue-api/internal/monitoring"
	"github.com/treytartt/honeydue-api/internal/push"
	"github.com/treytartt/honeydue-api/internal/repositories"
	"github.com/treytartt/honeydue-api/internal/services"
)

// Dependencies holds optional services for admin routes
type Dependencies struct {
	EmailService        *services.EmailService
	PushClient          *push.Client
	OnboardingService   *services.OnboardingEmailService
	MonitoringHandler   *monitoring.Handler
}

// SetupRoutes configures all admin routes
func SetupRoutes(router *echo.Echo, db *gorm.DB, cfg *config.Config, deps *Dependencies) {
	// Create repositories
	adminRepo := repositories.NewAdminRepository(db)

	// Create handlers
	authHandler := handlers.NewAdminAuthHandler(adminRepo, cfg)

	// Admin API group
	admin := router.Group("/api/admin")
	{
		// Public auth routes (no auth required)
		auth := admin.Group("/auth")
		{
			auth.POST("/login", authHandler.Login)
		}

		// Protected routes (require admin JWT)
		protected := admin.Group("")
		protected.Use(middleware.AdminAuthMiddleware(cfg, adminRepo))
		{
			// Auth routes that require authentication
			protectedAuth := protected.Group("/auth")
			{
				protectedAuth.POST("/logout", authHandler.Logout)
				protectedAuth.GET("/me", authHandler.Me)
				protectedAuth.POST("/refresh", authHandler.RefreshToken)
			}

			// User management
			userHandler := handlers.NewAdminUserHandler(db)
			users := protected.Group("/users")
			{
				users.GET("", userHandler.List)
				users.POST("", userHandler.Create)
				users.GET("/:id", userHandler.Get)
				users.PUT("/:id", userHandler.Update)
				users.DELETE("/:id", userHandler.Delete)
				users.DELETE("/bulk", userHandler.BulkDelete)
			}

			// Residence management
			residenceHandler := handlers.NewAdminResidenceHandler(db)
			residences := protected.Group("/residences")
			{
				residences.GET("", residenceHandler.List)
				residences.POST("", residenceHandler.Create)
				residences.DELETE("/bulk", residenceHandler.BulkDelete)
				residences.GET("/:id", residenceHandler.Get)
				residences.PUT("/:id", residenceHandler.Update)
				residences.DELETE("/:id", residenceHandler.Delete)
			}

			// Task management
			taskHandler := handlers.NewAdminTaskHandler(db)
			tasks := protected.Group("/tasks")
			{
				tasks.GET("", taskHandler.List)
				tasks.POST("", taskHandler.Create)
				tasks.DELETE("/bulk", taskHandler.BulkDelete)
				tasks.GET("/:id", taskHandler.Get)
				tasks.PUT("/:id", taskHandler.Update)
				tasks.DELETE("/:id", taskHandler.Delete)
			}

			// Contractor management
			contractorHandler := handlers.NewAdminContractorHandler(db)
			contractors := protected.Group("/contractors")
			{
				contractors.GET("", contractorHandler.List)
				contractors.POST("", contractorHandler.Create)
				contractors.DELETE("/bulk", contractorHandler.BulkDelete)
				contractors.GET("/:id", contractorHandler.Get)
				contractors.PUT("/:id", contractorHandler.Update)
				contractors.DELETE("/:id", contractorHandler.Delete)
			}

			// Document management
			documentHandler := handlers.NewAdminDocumentHandler(db)
			documents := protected.Group("/documents")
			{
				documents.GET("", documentHandler.List)
				documents.POST("", documentHandler.Create)
				documents.DELETE("/bulk", documentHandler.BulkDelete)
				documents.GET("/:id", documentHandler.Get)
				documents.PUT("/:id", documentHandler.Update)
				documents.DELETE("/:id", documentHandler.Delete)
			}

			// Notification management
			var emailService *services.EmailService
			var pushClient *push.Client
			if deps != nil {
				emailService = deps.EmailService
				pushClient = deps.PushClient
			}
			notificationHandler := handlers.NewAdminNotificationHandler(db, emailService, pushClient)
			notifications := protected.Group("/notifications")
			{
				notifications.GET("", notificationHandler.List)
				notifications.GET("/stats", notificationHandler.GetStats)
				notifications.POST("/send-test", notificationHandler.SendTestNotification)
				notifications.GET("/:id", notificationHandler.Get)
				notifications.PUT("/:id", notificationHandler.Update)
				notifications.DELETE("/:id", notificationHandler.Delete)
			}

			// Email test endpoint
			emails := protected.Group("/emails")
			{
				emails.POST("/send-test", notificationHandler.SendTestEmail)
				emails.POST("/send-post-verification", notificationHandler.SendPostVerificationEmail)
			}

			// Subscription management
			subscriptionHandler := handlers.NewAdminSubscriptionHandler(db)
			subscriptions := protected.Group("/subscriptions")
			{
				subscriptions.GET("", subscriptionHandler.List)
				subscriptions.GET("/stats", subscriptionHandler.GetStats)
				subscriptions.GET("/user/:user_id", subscriptionHandler.GetByUser)
				subscriptions.GET("/:id", subscriptionHandler.Get)
				subscriptions.PUT("/:id", subscriptionHandler.Update)
			}

			// Dashboard stats
			dashboardHandler := handlers.NewAdminDashboardHandler(db)
			protected.GET("/dashboard/stats", dashboardHandler.GetStats)

			// Auth token management
			authTokenHandler := handlers.NewAdminAuthTokenHandler(db)
			authTokens := protected.Group("/auth-tokens")
			{
				authTokens.GET("", authTokenHandler.List)
				authTokens.DELETE("/bulk", authTokenHandler.BulkDelete)
				authTokens.GET("/:id", authTokenHandler.Get)
				authTokens.DELETE("/:id", authTokenHandler.Delete)
			}

			// Task completion management
			completionHandler := handlers.NewAdminCompletionHandler(db)
			completions := protected.Group("/completions")
			{
				completions.GET("", completionHandler.List)
				completions.DELETE("/bulk", completionHandler.BulkDelete)
				completions.GET("/:id", completionHandler.Get)
				completions.PUT("/:id", completionHandler.Update)
				completions.DELETE("/:id", completionHandler.Delete)
			}

			// Confirmation code management
			confirmationCodeHandler := handlers.NewAdminConfirmationCodeHandler(db)
			confirmationCodes := protected.Group("/confirmation-codes")
			{
				confirmationCodes.GET("", confirmationCodeHandler.List)
				confirmationCodes.DELETE("/bulk", confirmationCodeHandler.BulkDelete)
				confirmationCodes.GET("/:id", confirmationCodeHandler.Get)
				confirmationCodes.DELETE("/:id", confirmationCodeHandler.Delete)
			}

			// Share code management
			shareCodeHandler := handlers.NewAdminShareCodeHandler(db)
			shareCodes := protected.Group("/share-codes")
			{
				shareCodes.GET("", shareCodeHandler.List)
				shareCodes.DELETE("/bulk", shareCodeHandler.BulkDelete)
				shareCodes.GET("/:id", shareCodeHandler.Get)
				shareCodes.PUT("/:id", shareCodeHandler.Update)
				shareCodes.DELETE("/:id", shareCodeHandler.Delete)
			}

			// Password reset code management
			passwordResetCodeHandler := handlers.NewAdminPasswordResetCodeHandler(db)
			passwordResetCodes := protected.Group("/password-reset-codes")
			{
				passwordResetCodes.GET("", passwordResetCodeHandler.List)
				passwordResetCodes.DELETE("/bulk", passwordResetCodeHandler.BulkDelete)
				passwordResetCodes.GET("/:id", passwordResetCodeHandler.Get)
				passwordResetCodes.DELETE("/:id", passwordResetCodeHandler.Delete)
			}

			// Push notification devices management
			deviceHandler := handlers.NewAdminDeviceHandler(db)
			devices := protected.Group("/devices")
			{
				devices.GET("/stats", deviceHandler.GetStats)
				devices.GET("/apns", deviceHandler.ListAPNS)
				devices.DELETE("/apns/bulk", deviceHandler.BulkDeleteAPNS)
				devices.PUT("/apns/:id", deviceHandler.UpdateAPNS)
				devices.DELETE("/apns/:id", deviceHandler.DeleteAPNS)
				devices.GET("/gcm", deviceHandler.ListGCM)
				devices.DELETE("/gcm/bulk", deviceHandler.BulkDeleteGCM)
				devices.PUT("/gcm/:id", deviceHandler.UpdateGCM)
				devices.DELETE("/gcm/:id", deviceHandler.DeleteGCM)
			}

			// Feature benefits management
			featureBenefitHandler := handlers.NewAdminFeatureBenefitHandler(db)
			featureBenefits := protected.Group("/feature-benefits")
			{
				featureBenefits.GET("", featureBenefitHandler.List)
				featureBenefits.POST("", featureBenefitHandler.Create)
				featureBenefits.GET("/:id", featureBenefitHandler.Get)
				featureBenefits.PUT("/:id", featureBenefitHandler.Update)
				featureBenefits.DELETE("/:id", featureBenefitHandler.Delete)
			}

			// Promotions management
			promotionHandler := handlers.NewAdminPromotionHandler(db)
			promotions := protected.Group("/promotions")
			{
				promotions.GET("", promotionHandler.List)
				promotions.POST("", promotionHandler.Create)
				promotions.GET("/:id", promotionHandler.Get)
				promotions.PUT("/:id", promotionHandler.Update)
				promotions.DELETE("/:id", promotionHandler.Delete)
			}

			// Lookup tables management
			lookupHandler := handlers.NewAdminLookupHandler(db)

			// Task Categories
			categories := protected.Group("/lookups/categories")
			{
				categories.GET("", lookupHandler.ListCategories)
				categories.POST("", lookupHandler.CreateCategory)
				categories.PUT("/:id", lookupHandler.UpdateCategory)
				categories.DELETE("/:id", lookupHandler.DeleteCategory)
			}

			// Task Priorities
			priorities := protected.Group("/lookups/priorities")
			{
				priorities.GET("", lookupHandler.ListPriorities)
				priorities.POST("", lookupHandler.CreatePriority)
				priorities.PUT("/:id", lookupHandler.UpdatePriority)
				priorities.DELETE("/:id", lookupHandler.DeletePriority)
			}

			// Task Frequencies
			frequencies := protected.Group("/lookups/frequencies")
			{
				frequencies.GET("", lookupHandler.ListFrequencies)
				frequencies.POST("", lookupHandler.CreateFrequency)
				frequencies.PUT("/:id", lookupHandler.UpdateFrequency)
				frequencies.DELETE("/:id", lookupHandler.DeleteFrequency)
			}

			// Notification Schedules (read-only, shows schedule for each frequency)
			protected.GET("/lookups/notification-schedules", lookupHandler.GetNotificationSchedules)

			// Residence Types
			residenceTypes := protected.Group("/lookups/residence-types")
			{
				residenceTypes.GET("", lookupHandler.ListResidenceTypes)
				residenceTypes.POST("", lookupHandler.CreateResidenceType)
				residenceTypes.PUT("/:id", lookupHandler.UpdateResidenceType)
				residenceTypes.DELETE("/:id", lookupHandler.DeleteResidenceType)
			}

			// Contractor Specialties
			specialties := protected.Group("/lookups/specialties")
			{
				specialties.GET("", lookupHandler.ListSpecialties)
				specialties.POST("", lookupHandler.CreateSpecialty)
				specialties.PUT("/:id", lookupHandler.UpdateSpecialty)
				specialties.DELETE("/:id", lookupHandler.DeleteSpecialty)
			}

			// Task Templates management
			taskTemplateHandler := handlers.NewAdminTaskTemplateHandler(db)
			taskTemplates := protected.Group("/task-templates")
			{
				taskTemplates.GET("", taskTemplateHandler.ListTemplates)
				taskTemplates.POST("", taskTemplateHandler.CreateTemplate)
				taskTemplates.POST("/bulk", taskTemplateHandler.BulkCreate)
				taskTemplates.GET("/:id", taskTemplateHandler.GetTemplate)
				taskTemplates.PUT("/:id", taskTemplateHandler.UpdateTemplate)
				taskTemplates.DELETE("/:id", taskTemplateHandler.DeleteTemplate)
				taskTemplates.POST("/:id/toggle-active", taskTemplateHandler.ToggleActive)
			}

			// Admin user management
			adminUserHandler := handlers.NewAdminUserManagementHandler(db)
			adminUsers := protected.Group("/admin-users")
			{
				adminUsers.GET("", adminUserHandler.List)
				adminUsers.POST("", adminUserHandler.Create)
				adminUsers.GET("/:id", adminUserHandler.Get)
				adminUsers.PUT("/:id", adminUserHandler.Update)
				adminUsers.DELETE("/:id", adminUserHandler.Delete)
			}

			// Notification preferences management
			notifPrefsHandler := handlers.NewAdminNotificationPrefsHandler(db)
			notifPrefs := protected.Group("/notification-prefs")
			{
				notifPrefs.GET("", notifPrefsHandler.List)
				notifPrefs.GET("/:id", notifPrefsHandler.Get)
				notifPrefs.PUT("/:id", notifPrefsHandler.Update)
				notifPrefs.DELETE("/:id", notifPrefsHandler.Delete)
				notifPrefs.GET("/user/:user_id", notifPrefsHandler.GetByUser)
			}

			// User profile management
			userProfileHandler := handlers.NewAdminUserProfileHandler(db)
			userProfiles := protected.Group("/user-profiles")
			{
				userProfiles.GET("", userProfileHandler.List)
				userProfiles.DELETE("/bulk", userProfileHandler.BulkDelete)
				userProfiles.GET("/:id", userProfileHandler.Get)
				userProfiles.PUT("/:id", userProfileHandler.Update)
				userProfiles.DELETE("/:id", userProfileHandler.Delete)
				userProfiles.GET("/user/:user_id", userProfileHandler.GetByUser)
			}

			// Apple social auth management
			appleSocialAuthHandler := handlers.NewAdminAppleSocialAuthHandler(db)
			appleSocialAuth := protected.Group("/apple-social-auth")
			{
				appleSocialAuth.GET("", appleSocialAuthHandler.List)
				appleSocialAuth.DELETE("/bulk", appleSocialAuthHandler.BulkDelete)
				appleSocialAuth.GET("/:id", appleSocialAuthHandler.Get)
				appleSocialAuth.PUT("/:id", appleSocialAuthHandler.Update)
				appleSocialAuth.DELETE("/:id", appleSocialAuthHandler.Delete)
				appleSocialAuth.GET("/user/:user_id", appleSocialAuthHandler.GetByUser)
			}

			// Task completion images management
			completionImageHandler := handlers.NewAdminCompletionImageHandler(db)
			completionImages := protected.Group("/completion-images")
			{
				completionImages.GET("", completionImageHandler.List)
				completionImages.POST("", completionImageHandler.Create)
				completionImages.DELETE("/bulk", completionImageHandler.BulkDelete)
				completionImages.GET("/:id", completionImageHandler.Get)
				completionImages.PUT("/:id", completionImageHandler.Update)
				completionImages.DELETE("/:id", completionImageHandler.Delete)
			}

			// Document images management
			documentImageHandler := handlers.NewAdminDocumentImageHandler(db)
			documentImages := protected.Group("/document-images")
			{
				documentImages.GET("", documentImageHandler.List)
				documentImages.POST("", documentImageHandler.Create)
				documentImages.DELETE("/bulk", documentImageHandler.BulkDelete)
				documentImages.GET("/:id", documentImageHandler.Get)
				documentImages.PUT("/:id", documentImageHandler.Update)
				documentImages.DELETE("/:id", documentImageHandler.Delete)
			}

			// System settings management (super admin only)
			settingsHandler := handlers.NewAdminSettingsHandler(db)
			settings := protected.Group("/settings")
			settings.Use(middleware.RequireSuperAdmin())
			{
				settings.GET("", settingsHandler.GetSettings)
				settings.PUT("", settingsHandler.UpdateSettings)
				settings.POST("/seed-lookups", settingsHandler.SeedLookups)
				settings.POST("/seed-test-data", settingsHandler.SeedTestData)
				settings.POST("/seed-task-templates", settingsHandler.SeedTaskTemplates)
				settings.POST("/clear-all-data", settingsHandler.ClearAllData)
				settings.POST("/clear-stuck-jobs", settingsHandler.ClearStuckJobs)
			}

			// Limitations management (tier limits, upgrade triggers)
			limitationsHandler := handlers.NewAdminLimitationsHandler(db)
			limitations := protected.Group("/limitations")
			{
				// Settings (enable_limitations toggle)
				limitations.GET("/settings", limitationsHandler.GetSettings)
				limitations.PUT("/settings", limitationsHandler.UpdateSettings)

				// Tier Limits
				limitations.GET("/tier-limits", limitationsHandler.ListTierLimits)
				limitations.GET("/tier-limits/:tier", limitationsHandler.GetTierLimits)
				limitations.PUT("/tier-limits/:tier", limitationsHandler.UpdateTierLimits)

				// Upgrade Triggers
				limitations.GET("/upgrade-triggers/keys", limitationsHandler.GetAvailableTriggerKeys)
				limitations.GET("/upgrade-triggers", limitationsHandler.ListUpgradeTriggers)
				limitations.POST("/upgrade-triggers", limitationsHandler.CreateUpgradeTrigger)
				limitations.GET("/upgrade-triggers/:id", limitationsHandler.GetUpgradeTrigger)
				limitations.PUT("/upgrade-triggers/:id", limitationsHandler.UpdateUpgradeTrigger)
				limitations.DELETE("/upgrade-triggers/:id", limitationsHandler.DeleteUpgradeTrigger)
			}

			// Onboarding emails management
			var onboardingService *services.OnboardingEmailService
			if deps != nil {
				onboardingService = deps.OnboardingService
			}
			onboardingHandler := handlers.NewAdminOnboardingHandler(db, onboardingService)
			onboardingEmails := protected.Group("/onboarding-emails")
			{
				onboardingEmails.GET("", onboardingHandler.List)
				onboardingEmails.GET("/stats", onboardingHandler.GetStats)
				onboardingEmails.POST("/send", onboardingHandler.Send)
				onboardingEmails.DELETE("/bulk", onboardingHandler.BulkDelete)
				onboardingEmails.GET("/user/:user_id", onboardingHandler.GetByUser)
				onboardingEmails.GET("/:id", onboardingHandler.Get)
				onboardingEmails.DELETE("/:id", onboardingHandler.Delete)
			}

			// System monitoring (logs, stats, websocket)
			if deps != nil && deps.MonitoringHandler != nil {
				monitoringGroup := protected.Group("/monitoring")
				{
					monitoringGroup.GET("/logs", deps.MonitoringHandler.GetLogs)
					monitoringGroup.GET("/stats", deps.MonitoringHandler.GetStats)
					monitoringGroup.DELETE("/logs", deps.MonitoringHandler.ClearLogs)
					monitoringGroup.GET("/ws", deps.MonitoringHandler.WebSocket)
				}
			}
		}
	}

	// Proxy admin panel requests to Next.js server
	setupAdminProxy(router)
}

// setupAdminProxy configures reverse proxy to the Next.js admin panel.
// When ADMIN_HOST is set (e.g. admin.myhoneydue.com), requests to that
// subdomain are proxied to Next.js at the root path. Requests to /admin/*
// on the admin subdomain redirect to the main web app.
func setupAdminProxy(router *echo.Echo) {
	// Get admin panel URL from env, default to localhost:3001
	// Note: In production (Dokku), Next.js runs on internal port 3001
	adminURL := os.Getenv("ADMIN_PANEL_URL")
	if adminURL == "" {
		adminURL = "http://127.0.0.1:3001"
	}

	target, err := url.Parse(adminURL)
	if err != nil {
		return
	}

	proxy := httputil.NewSingleHostReverseProxy(target)

	// Admin subdomain: proxy all non-API requests to Next.js
	adminHost := os.Getenv("ADMIN_HOST")
	webAppURL := os.Getenv("WEB_APP_URL")
	if webAppURL == "" {
		webAppURL = "https://myhoneydue.com"
	}

	if adminHost != "" {
		router.Use(func(next echo.HandlerFunc) echo.HandlerFunc {
			return func(c echo.Context) error {
				if c.Request().Host != adminHost {
					return next(c)
				}

				path := c.Request().URL.Path

				// Redirect /admin/* to the main web app
				if strings.HasPrefix(path, "/admin") {
					return c.Redirect(http.StatusMovedPermanently, webAppURL)
				}

				// Let /api/* routes pass through to the Go API
				if strings.HasPrefix(path, "/api/") {
					return next(c)
				}

				// Proxy everything else to Next.js admin
				proxy.ServeHTTP(c.Response(), c.Request())
				return nil
			}
		})
	}

	// Proxy Next.js static assets — only when the request comes from a
	// known host to prevent SSRF via crafted Host headers.
	var allowedProxyHosts []string
	if adminHost != "" {
		allowedProxyHosts = append(allowedProxyHosts, adminHost)
	}
	// Also allow localhost variants for development
	allowedProxyHosts = append(allowedProxyHosts,
		"localhost:3001", "127.0.0.1:3001",
		"localhost:8000", "127.0.0.1:8000",
	)
	hostCheck := middleware.HostCheck(allowedProxyHosts)

	router.Any("/_next/*", func(c echo.Context) error {
		proxy.ServeHTTP(c.Response(), c.Request())
		return nil
	}, hostCheck)
}
