package handlers

import (
	"context"
	"fmt"
	"net/http"
	"os"
	"path/filepath"
	"strings"

	"github.com/labstack/echo/v4"
	"github.com/rs/zerolog/log"
	"gorm.io/gorm"

	"github.com/treytartt/honeydue-api/internal/models"
	"github.com/treytartt/honeydue-api/internal/services"
)

// AdminSettingsHandler handles system settings management
type AdminSettingsHandler struct {
	db *gorm.DB
}

// NewAdminSettingsHandler creates a new handler
func NewAdminSettingsHandler(db *gorm.DB) *AdminSettingsHandler {
	return &AdminSettingsHandler{db: db}
}

// SettingsResponse represents the settings response
type SettingsResponse struct {
	EnableLimitations bool `json:"enable_limitations"`
	EnableMonitoring  bool `json:"enable_monitoring"`
	TrialEnabled      bool `json:"trial_enabled"`
	TrialDurationDays int  `json:"trial_duration_days"`
}

// GetSettings handles GET /api/admin/settings
func (h *AdminSettingsHandler) GetSettings(c echo.Context) error {
	var settings models.SubscriptionSettings
	if err := h.db.First(&settings, 1).Error; err != nil {
		if err == gorm.ErrRecordNotFound {
			// Create default settings
			settings = models.SubscriptionSettings{
				ID:                1,
				EnableLimitations: false,
				EnableMonitoring:  true,
				TrialEnabled:      true,
				TrialDurationDays: 14,
			}
			if err := h.db.Create(&settings).Error; err != nil {
				return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to create default settings"})
			}
		} else {
			return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to fetch settings"})
		}
	}

	return c.JSON(http.StatusOK, SettingsResponse{
		EnableLimitations: settings.EnableLimitations,
		EnableMonitoring:  settings.EnableMonitoring,
		TrialEnabled:      settings.TrialEnabled,
		TrialDurationDays: settings.TrialDurationDays,
	})
}

// UpdateSettingsRequest represents the update request
type UpdateSettingsRequest struct {
	EnableLimitations *bool `json:"enable_limitations"`
	EnableMonitoring  *bool `json:"enable_monitoring"`
	TrialEnabled      *bool `json:"trial_enabled"`
	TrialDurationDays *int  `json:"trial_duration_days"`
}

// UpdateSettings handles PUT /api/admin/settings
func (h *AdminSettingsHandler) UpdateSettings(c echo.Context) error {
	var req UpdateSettingsRequest
	if err := c.Bind(&req); err != nil {
		return c.JSON(http.StatusBadRequest, map[string]interface{}{"error": "Invalid request body"})
	}

	var settings models.SubscriptionSettings
	if err := h.db.First(&settings, 1).Error; err != nil {
		if err == gorm.ErrRecordNotFound {
			settings = models.SubscriptionSettings{
				ID:                1,
				EnableMonitoring:  true,
				TrialEnabled:      true,
				TrialDurationDays: 14,
			}
		} else {
			return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to fetch settings"})
		}
	}

	if req.EnableLimitations != nil {
		settings.EnableLimitations = *req.EnableLimitations
	}

	if req.EnableMonitoring != nil {
		settings.EnableMonitoring = *req.EnableMonitoring
	}

	if req.TrialEnabled != nil {
		settings.TrialEnabled = *req.TrialEnabled
	}

	if req.TrialDurationDays != nil {
		settings.TrialDurationDays = *req.TrialDurationDays
	}

	if err := h.db.Save(&settings).Error; err != nil {
		return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to update settings"})
	}

	return c.JSON(http.StatusOK, SettingsResponse{
		EnableLimitations: settings.EnableLimitations,
		EnableMonitoring:  settings.EnableMonitoring,
		TrialEnabled:      settings.TrialEnabled,
		TrialDurationDays: settings.TrialDurationDays,
	})
}

// SeedLookups handles POST /api/admin/settings/seed-lookups
// Seeds both lookup tables AND task templates, then caches all lookups in Redis
func (h *AdminSettingsHandler) SeedLookups(c echo.Context) error {
	// First seed lookup tables
	if err := h.runSeedFile("001_lookups.sql"); err != nil {
		return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to seed lookups"})
	}

	// Then seed task templates
	if err := h.runSeedFile("003_task_templates.sql"); err != nil {
		return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to seed task templates"})
	}

	// Cache all lookups in Redis
	cached, cacheErr := h.cacheAllLookups(c.Request().Context())
	if cacheErr != nil {
		log.Warn().Err(cacheErr).Msg("Failed to cache lookups in Redis, but seed was successful")
	}

	response := map[string]interface{}{
		"message":      "Lookup data and task templates seeded successfully",
		"redis_cached": cached,
	}

	return c.JSON(http.StatusOK, response)
}

// cacheAllLookups fetches all lookup data from the database and caches it in Redis
func (h *AdminSettingsHandler) cacheAllLookups(ctx context.Context) (bool, error) {
	cache := services.GetCache()
	if cache == nil {
		return false, fmt.Errorf("Redis cache not available")
	}

	// Fetch and cache task categories
	var categories []models.TaskCategory
	if err := h.db.Order("display_order ASC, name ASC").Find(&categories).Error; err != nil {
		return false, fmt.Errorf("failed to fetch categories: %w", err)
	}
	if err := cache.CacheCategories(ctx, categories); err != nil {
		return false, fmt.Errorf("failed to cache categories: %w", err)
	}
	log.Debug().Int("count", len(categories)).Msg("Cached task categories")

	// Fetch and cache task priorities
	var priorities []models.TaskPriority
	if err := h.db.Order("display_order ASC, level ASC").Find(&priorities).Error; err != nil {
		return false, fmt.Errorf("failed to fetch priorities: %w", err)
	}
	if err := cache.CachePriorities(ctx, priorities); err != nil {
		return false, fmt.Errorf("failed to cache priorities: %w", err)
	}
	log.Debug().Int("count", len(priorities)).Msg("Cached task priorities")

	// Fetch and cache task frequencies
	var frequencies []models.TaskFrequency
	if err := h.db.Order("display_order ASC, name ASC").Find(&frequencies).Error; err != nil {
		return false, fmt.Errorf("failed to fetch frequencies: %w", err)
	}
	if err := cache.CacheFrequencies(ctx, frequencies); err != nil {
		return false, fmt.Errorf("failed to cache frequencies: %w", err)
	}
	log.Debug().Int("count", len(frequencies)).Msg("Cached task frequencies")

	// Fetch and cache residence types
	var residenceTypes []models.ResidenceType
	if err := h.db.Order("name ASC").Find(&residenceTypes).Error; err != nil {
		return false, fmt.Errorf("failed to fetch residence types: %w", err)
	}
	if err := cache.CacheResidenceTypes(ctx, residenceTypes); err != nil {
		return false, fmt.Errorf("failed to cache residence types: %w", err)
	}
	log.Debug().Int("count", len(residenceTypes)).Msg("Cached residence types")

	// Fetch and cache contractor specialties
	var specialties []models.ContractorSpecialty
	if err := h.db.Order("display_order ASC, name ASC").Find(&specialties).Error; err != nil {
		return false, fmt.Errorf("failed to fetch specialties: %w", err)
	}
	if err := cache.CacheSpecialties(ctx, specialties); err != nil {
		return false, fmt.Errorf("failed to cache specialties: %w", err)
	}
	log.Debug().Int("count", len(specialties)).Msg("Cached contractor specialties")

	// Fetch and cache task templates (only active ones)
	var taskTemplates []models.TaskTemplate
	if err := h.db.Preload("Category").Preload("Frequency").
		Where("is_active = ?", true).
		Order("display_order ASC, title ASC").
		Find(&taskTemplates).Error; err != nil {
		return false, fmt.Errorf("failed to fetch task templates: %w", err)
	}
	if err := cache.CacheTaskTemplates(ctx, taskTemplates); err != nil {
		return false, fmt.Errorf("failed to cache task templates: %w", err)
	}
	log.Debug().Int("count", len(taskTemplates)).Msg("Cached task templates")

	// Build and cache the unified seeded data response
	// Import the grouped response type
	seededData := map[string]interface{}{
		"residence_types":        residenceTypes,
		"task_categories":        categories,
		"task_priorities":        priorities,
		"task_frequencies":       frequencies,
		"contractor_specialties": specialties,
		"task_templates":         buildGroupedTemplates(taskTemplates),
	}

	etag, err := cache.CacheSeededData(ctx, seededData)
	if err != nil {
		return false, fmt.Errorf("failed to cache seeded data: %w", err)
	}
	log.Debug().Str("etag", etag).Msg("Cached unified seeded data")

	log.Info().Msg("All lookup data cached in Redis successfully")
	return true, nil
}

// buildGroupedTemplates groups task templates by category for the seeded data response
func buildGroupedTemplates(templates []models.TaskTemplate) map[string]interface{} {
	type templateResponse struct {
		ID           uint                   `json:"id"`
		Title        string                 `json:"title"`
		Description  string                 `json:"description"`
		CategoryID   *uint                  `json:"category_id"`
		Category     map[string]interface{} `json:"category,omitempty"`
		FrequencyID  *uint                  `json:"frequency_id"`
		Frequency    map[string]interface{} `json:"frequency,omitempty"`
		IconIOS      string                 `json:"icon_ios"`
		IconAndroid  string                 `json:"icon_android"`
		Tags         []string               `json:"tags"`
		DisplayOrder int                    `json:"display_order"`
		IsActive     bool                   `json:"is_active"`
	}

	type categoryGroup struct {
		CategoryName string             `json:"category_name"`
		CategoryID   *uint              `json:"category_id"`
		Templates    []templateResponse `json:"templates"`
		Count        int                `json:"count"`
	}

	categoryMap := make(map[string]*categoryGroup)
	categoryOrder := []string{}

	for _, t := range templates {
		categoryName := "Uncategorized"
		var categoryID *uint
		if t.Category != nil {
			categoryName = t.Category.Name
			categoryID = &t.Category.ID
		}

		if _, exists := categoryMap[categoryName]; !exists {
			categoryMap[categoryName] = &categoryGroup{
				CategoryName: categoryName,
				CategoryID:   categoryID,
				Templates:    []templateResponse{},
			}
			categoryOrder = append(categoryOrder, categoryName)
		}

		resp := templateResponse{
			ID:           t.ID,
			Title:        t.Title,
			Description:  t.Description,
			CategoryID:   t.CategoryID,
			FrequencyID:  t.FrequencyID,
			IconIOS:      t.IconIOS,
			IconAndroid:  t.IconAndroid,
			Tags:         parseTags(t.Tags),
			DisplayOrder: t.DisplayOrder,
			IsActive:     t.IsActive,
		}

		if t.Category != nil {
			resp.Category = map[string]interface{}{
				"id":            t.Category.ID,
				"name":          t.Category.Name,
				"description":   t.Category.Description,
				"icon":          t.Category.Icon,
				"color":         t.Category.Color,
				"display_order": t.Category.DisplayOrder,
			}
		}
		if t.Frequency != nil {
			resp.Frequency = map[string]interface{}{
				"id":            t.Frequency.ID,
				"name":          t.Frequency.Name,
				"days":          t.Frequency.Days,
				"display_order": t.Frequency.DisplayOrder,
			}
		}

		categoryMap[categoryName].Templates = append(categoryMap[categoryName].Templates, resp)
	}

	categories := make([]categoryGroup, len(categoryOrder))
	totalCount := 0
	for i, name := range categoryOrder {
		group := categoryMap[name]
		group.Count = len(group.Templates)
		totalCount += group.Count
		categories[i] = *group
	}

	return map[string]interface{}{
		"categories":  categories,
		"total_count": totalCount,
	}
}

// parseTags splits a comma-separated tags string into a slice
func parseTags(tags string) []string {
	if tags == "" {
		return []string{}
	}
	parts := strings.Split(tags, ",")
	result := make([]string, 0, len(parts))
	for _, p := range parts {
		trimmed := strings.TrimSpace(p)
		if trimmed != "" {
			result = append(result, trimmed)
		}
	}
	return result
}

// SeedTestData handles POST /api/admin/settings/seed-test-data
func (h *AdminSettingsHandler) SeedTestData(c echo.Context) error {
	if err := h.runSeedFile("002_test_data.sql"); err != nil {
		return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to seed test data"})
	}

	return c.JSON(http.StatusOK, map[string]interface{}{"message": "Test data seeded successfully"})
}

// SeedTaskTemplates handles POST /api/admin/settings/seed-task-templates
func (h *AdminSettingsHandler) SeedTaskTemplates(c echo.Context) error {
	if err := h.runSeedFile("003_task_templates.sql"); err != nil {
		return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to seed task templates"})
	}

	return c.JSON(http.StatusOK, map[string]interface{}{"message": "Task templates seeded successfully"})
}

// runSeedFile executes a seed SQL file
func (h *AdminSettingsHandler) runSeedFile(filename string) error {
	// Check multiple possible locations
	possiblePaths := []string{
		filepath.Join("seeds", filename),
		filepath.Join("./seeds", filename),
		filepath.Join("/app/seeds", filename),
	}

	var sqlContent []byte
	var err error
	for _, path := range possiblePaths {
		sqlContent, err = os.ReadFile(path)
		if err == nil {
			break
		}
	}

	if err != nil {
		return err
	}

	// Get the underlying *sql.DB to execute raw SQL without prepared statements
	sqlDB, err := h.db.DB()
	if err != nil {
		return err
	}

	// Split SQL into individual statements and execute each one
	// This is needed because GORM/PostgreSQL prepared statements don't support multiple commands
	statements := splitSQLStatements(string(sqlContent))

	for i, stmt := range statements {
		stmt = strings.TrimSpace(stmt)
		if stmt == "" {
			continue
		}
		// Use the raw sql.DB to avoid GORM's prepared statement handling
		if _, err := sqlDB.Exec(stmt); err != nil {
			// Include statement number and first 100 chars for debugging
			preview := stmt
			if len(preview) > 100 {
				preview = preview[:100] + "..."
			}
			return fmt.Errorf("statement %d failed: %v\nStatement: %s", i+1, err, preview)
		}
	}

	return nil
}

// splitSQLStatements splits SQL content into individual statements
func splitSQLStatements(sql string) []string {
	var statements []string
	var current strings.Builder
	inString := false
	stringChar := byte(0)

	for i := 0; i < len(sql); i++ {
		c := sql[i]

		// Handle string literals (don't split on semicolons inside strings)
		if (c == '\'' || c == '"') && (i == 0 || sql[i-1] != '\\') {
			if !inString {
				inString = true
				stringChar = c
			} else if c == stringChar {
				// Check for escaped quote ('')
				if c == '\'' && i+1 < len(sql) && sql[i+1] == '\'' {
					current.WriteByte(c)
					i++
					current.WriteByte(sql[i])
					continue
				}
				inString = false
			}
		}

		// Split on semicolon if not in string
		if c == ';' && !inString {
			current.WriteByte(c)
			stmt := strings.TrimSpace(current.String())
			if stmt != "" && !isCommentOnly(stmt) {
				statements = append(statements, stmt)
			}
			current.Reset()
			continue
		}

		current.WriteByte(c)
	}

	// Don't forget the last statement if it doesn't end with semicolon
	if stmt := strings.TrimSpace(current.String()); stmt != "" && !isCommentOnly(stmt) {
		statements = append(statements, stmt)
	}

	return statements
}

// isCommentOnly checks if the statement is only comments
func isCommentOnly(stmt string) bool {
	lines := strings.Split(stmt, "\n")
	for _, line := range lines {
		line = strings.TrimSpace(line)
		if line != "" && !strings.HasPrefix(line, "--") {
			return false
		}
	}
	return true
}

// ClearAllDataResponse represents the response after clearing data
type ClearAllDataResponse struct {
	Message        string `json:"message"`
	UsersDeleted   int64  `json:"users_deleted"`
	PreservedUsers int64  `json:"preserved_users"`
}

// ClearStuckJobsResponse represents the response after clearing stuck Redis jobs
type ClearStuckJobsResponse struct {
	Message      string   `json:"message"`
	KeysDeleted  int      `json:"keys_deleted"`
	DeletedKeys  []string `json:"deleted_keys"`
}

// ClearStuckJobs handles POST /api/admin/settings/clear-stuck-jobs
// This clears stuck/failed asynq worker jobs from Redis
func (h *AdminSettingsHandler) ClearStuckJobs(c echo.Context) error {
	cache := services.GetCache()
	if cache == nil {
		return c.JSON(http.StatusServiceUnavailable, map[string]interface{}{"error": "Redis cache not available"})
	}

	ctx := c.Request().Context()
	client := cache.Client()

	var deletedKeys []string

	// Patterns for asynq job keys that can get stuck
	patterns := []string{
		"asynq:{default}:retry",           // Retry queue
		"asynq:{default}:archived",        // Archived/dead jobs
		"asynq:{default}:t:*",             // Individual task metadata
	}

	for _, pattern := range patterns {
		if strings.Contains(pattern, "*") {
			// Use SCAN for patterns with wildcards
			iter := client.Scan(ctx, 0, pattern, 0).Iterator()
			for iter.Next(ctx) {
				key := iter.Val()
				if err := client.Del(ctx, key).Err(); err != nil {
					log.Warn().Err(err).Str("key", key).Msg("Failed to delete key")
					continue
				}
				deletedKeys = append(deletedKeys, key)
			}
			if err := iter.Err(); err != nil {
				log.Warn().Err(err).Str("pattern", pattern).Msg("Error scanning keys")
			}
		} else {
			// Direct key deletion
			exists, err := client.Exists(ctx, pattern).Result()
			if err != nil {
				log.Warn().Err(err).Str("key", pattern).Msg("Failed to check key existence")
				continue
			}
			if exists > 0 {
				if err := client.Del(ctx, pattern).Err(); err != nil {
					log.Warn().Err(err).Str("key", pattern).Msg("Failed to delete key")
					continue
				}
				deletedKeys = append(deletedKeys, pattern)
			}
		}
	}

	log.Info().Int("count", len(deletedKeys)).Strs("keys", deletedKeys).Msg("Cleared stuck Redis jobs")

	return c.JSON(http.StatusOK, ClearStuckJobsResponse{
		Message:     "Stuck jobs cleared successfully",
		KeysDeleted: len(deletedKeys),
		DeletedKeys: deletedKeys,
	})
}

// ClearAllData handles POST /api/admin/settings/clear-all-data
// This clears all data except super admin accounts and lookup tables
func (h *AdminSettingsHandler) ClearAllData(c echo.Context) error {
	// Start a transaction
	tx := h.db.Begin()
	if tx.Error != nil {
		return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to start transaction"})
	}

	defer func() {
		if r := recover(); r != nil {
			tx.Rollback()
		}
	}()

	// Get IDs of users to preserve (superusers)
	var preservedUserIDs []uint
	if err := tx.Model(&models.User{}).
		Where("is_superuser = ?", true).
		Pluck("id", &preservedUserIDs).Error; err != nil {
		tx.Rollback()
		return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to get superuser IDs"})
	}

	// Count users that will be deleted
	var usersToDelete int64
	if err := tx.Model(&models.User{}).
		Where("is_superuser = ?", false).
		Count(&usersToDelete).Error; err != nil {
		tx.Rollback()
		return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to count users"})
	}

	// Delete in order to respect foreign key constraints
	// Order matters: delete from child tables first

	// 1. Delete task completion images
	if err := tx.Exec("DELETE FROM task_taskcompletionimage").Error; err != nil {
		tx.Rollback()
		return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to delete task completion images"})
	}

	// 2. Delete task completions
	if err := tx.Exec("DELETE FROM task_taskcompletion").Error; err != nil {
		tx.Rollback()
		return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to delete task completions"})
	}

	// 3. Delete notifications (must be before tasks since notifications have task_id FK)
	if len(preservedUserIDs) > 0 {
		if err := tx.Exec("DELETE FROM notifications_notification WHERE user_id NOT IN (?)", preservedUserIDs).Error; err != nil {
			tx.Rollback()
			return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to delete notifications"})
		}
	} else {
		if err := tx.Exec("DELETE FROM notifications_notification").Error; err != nil {
			tx.Rollback()
			return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to delete notifications"})
		}
	}

	// 4. Delete document images
	if err := tx.Exec("DELETE FROM task_documentimage").Error; err != nil {
		tx.Rollback()
		return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to delete document images"})
	}

	// 5. Delete documents
	if err := tx.Exec("DELETE FROM task_document").Error; err != nil {
		tx.Rollback()
		return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to delete documents"})
	}

	// 6. Delete task reminder logs (must be before tasks since reminder logs have task_id FK)
	// Check if table exists first to avoid aborting transaction
	var tableExists bool
	tx.Raw("SELECT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'task_reminderlog')").Scan(&tableExists)
	if tableExists {
		if err := tx.Exec("DELETE FROM task_reminderlog").Error; err != nil {
			tx.Rollback()
			return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to delete task reminder logs"})
		}
	}

	// 7. Delete tasks (must be before contractors since tasks reference contractors)
	if err := tx.Exec("DELETE FROM task_task").Error; err != nil {
		tx.Rollback()
		return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to delete tasks"})
	}

	// 8. Delete contractor specialties (many-to-many)
	if err := tx.Exec("DELETE FROM task_contractor_specialties").Error; err != nil {
		tx.Rollback()
		return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to delete contractor specialties"})
	}

	// 9. Delete contractors
	if err := tx.Exec("DELETE FROM task_contractor").Error; err != nil {
		tx.Rollback()
		return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to delete contractors"})
	}

	// 10. Delete residence_users (many-to-many for shared residences)
	if err := tx.Exec("DELETE FROM residence_residence_users").Error; err != nil {
		tx.Rollback()
		return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to delete residence users"})
	}

	// 11. Delete residence share codes (must be before residences since share codes have residence_id FK)
	if err := tx.Exec("DELETE FROM residence_residencesharecode").Error; err != nil {
		tx.Rollback()
		return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to delete residence share codes"})
	}

	// 12. Delete residences
	if err := tx.Exec("DELETE FROM residence_residence").Error; err != nil {
		tx.Rollback()
		return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to delete residences"})
	}

	// 13. Delete push devices for non-superusers (both APNS and GCM)
	if len(preservedUserIDs) > 0 {
		if err := tx.Exec("DELETE FROM push_notifications_apnsdevice WHERE user_id NOT IN (?)", preservedUserIDs).Error; err != nil {
			tx.Rollback()
			return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to delete APNS devices"})
		}
		if err := tx.Exec("DELETE FROM push_notifications_gcmdevice WHERE user_id NOT IN (?)", preservedUserIDs).Error; err != nil {
			tx.Rollback()
			return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to delete GCM devices"})
		}
	} else {
		if err := tx.Exec("DELETE FROM push_notifications_apnsdevice").Error; err != nil {
			tx.Rollback()
			return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to delete APNS devices"})
		}
		if err := tx.Exec("DELETE FROM push_notifications_gcmdevice").Error; err != nil {
			tx.Rollback()
			return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to delete GCM devices"})
		}
	}

	// 14. Delete notification preferences for non-superusers
	if len(preservedUserIDs) > 0 {
		if err := tx.Exec("DELETE FROM notifications_notificationpreference WHERE user_id NOT IN (?)", preservedUserIDs).Error; err != nil {
			tx.Rollback()
			return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to delete notification preferences"})
		}
	} else {
		if err := tx.Exec("DELETE FROM notifications_notificationpreference").Error; err != nil {
			tx.Rollback()
			return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to delete notification preferences"})
		}
	}

	// 15. Delete user subscriptions for non-superusers
	if len(preservedUserIDs) > 0 {
		if err := tx.Exec("DELETE FROM subscription_usersubscription WHERE user_id NOT IN (?)", preservedUserIDs).Error; err != nil {
			tx.Rollback()
			return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to delete subscriptions"})
		}
	} else {
		if err := tx.Exec("DELETE FROM subscription_usersubscription").Error; err != nil {
			tx.Rollback()
			return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to delete subscriptions"})
		}
	}

	// 16. Delete password reset codes for non-superusers
	if len(preservedUserIDs) > 0 {
		if err := tx.Exec("DELETE FROM user_passwordresetcode WHERE user_id NOT IN (?)", preservedUserIDs).Error; err != nil {
			tx.Rollback()
			return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to delete password reset codes"})
		}
	} else {
		if err := tx.Exec("DELETE FROM user_passwordresetcode").Error; err != nil {
			tx.Rollback()
			return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to delete password reset codes"})
		}
	}

	// 17. Delete confirmation codes for non-superusers
	if len(preservedUserIDs) > 0 {
		if err := tx.Exec("DELETE FROM user_confirmationcode WHERE user_id NOT IN (?)", preservedUserIDs).Error; err != nil {
			tx.Rollback()
			return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to delete confirmation codes"})
		}
	} else {
		if err := tx.Exec("DELETE FROM user_confirmationcode").Error; err != nil {
			tx.Rollback()
			return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to delete confirmation codes"})
		}
	}

	// 18. Delete auth tokens for non-superusers
	if len(preservedUserIDs) > 0 {
		if err := tx.Exec("DELETE FROM user_authtoken WHERE user_id NOT IN (?)", preservedUserIDs).Error; err != nil {
			tx.Rollback()
			return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to delete auth tokens"})
		}
	} else {
		if err := tx.Exec("DELETE FROM user_authtoken").Error; err != nil {
			tx.Rollback()
			return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to delete auth tokens"})
		}
	}

	// 19. Delete Apple social auth for non-superusers (Sign in with Apple)
	if len(preservedUserIDs) > 0 {
		if err := tx.Exec("DELETE FROM user_applesocialauth WHERE user_id NOT IN (?)", preservedUserIDs).Error; err != nil {
			tx.Rollback()
			return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to delete Apple social auth"})
		}
	} else {
		if err := tx.Exec("DELETE FROM user_applesocialauth").Error; err != nil {
			tx.Rollback()
			return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to delete Apple social auth"})
		}
	}

	// 20. Delete user profiles for non-superusers
	if len(preservedUserIDs) > 0 {
		if err := tx.Exec("DELETE FROM user_userprofile WHERE user_id NOT IN (?)", preservedUserIDs).Error; err != nil {
			tx.Rollback()
			return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to delete user profiles"})
		}
	} else {
		if err := tx.Exec("DELETE FROM user_userprofile").Error; err != nil {
			tx.Rollback()
			return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to delete user profiles"})
		}
	}

	// 21. Delete onboarding emails for non-superusers
	var onboardingEmailsExists bool
	tx.Raw("SELECT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'onboarding_emails')").Scan(&onboardingEmailsExists)
	if onboardingEmailsExists {
		if len(preservedUserIDs) > 0 {
			if err := tx.Exec("DELETE FROM onboarding_emails WHERE user_id NOT IN (?)", preservedUserIDs).Error; err != nil {
				tx.Rollback()
				return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to delete onboarding emails"})
			}
		} else {
			if err := tx.Exec("DELETE FROM onboarding_emails").Error; err != nil {
				tx.Rollback()
				return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to delete onboarding emails"})
			}
		}
	}

	// 22. Finally, delete non-superuser users
	// Always filter by is_superuser to be safe, regardless of preservedUserIDs
	if err := tx.Exec("DELETE FROM auth_user WHERE is_superuser = false").Error; err != nil {
		tx.Rollback()
		return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to delete users"})
	}

	// Commit the transaction
	if err := tx.Commit().Error; err != nil {
		return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to commit transaction"})
	}

	return c.JSON(http.StatusOK, ClearAllDataResponse{
		Message:        "All data cleared successfully (superadmin accounts preserved)",
		UsersDeleted:   usersToDelete,
		PreservedUsers: int64(len(preservedUserIDs)),
	})
}
