package controllers

import (
	"fmt"
	"net/http"
	"net/url"
	"os"
	"strconv"
	"strings"
	"time"

	"fotbal-club/internal/config"
	"fotbal-club/internal/models"
	"fotbal-club/internal/services"
	"fotbal-club/pkg/email"
	"fotbal-club/pkg/logger"
	"fotbal-club/pkg/utils"

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

type ContactController struct {
	DB           *gorm.DB
	emailService email.EmailService
}

// SendNewsletterDigest builds and sends a digest newsletter based on a template type (admin only)
// POST /api/v1/admin/newsletter/send-digest { type: "blogs|events|matches|scores|weekly", competitions?: "ABC, DEF" }
func (cc *ContactController) SendNewsletterDigest(c *gin.Context) {
	if c.GetString("userRole") != "admin" {
		c.JSON(http.StatusForbidden, gin.H{"error": "Access denied"})
		return
	}

	var input struct {
		Type         string `json:"type" binding:"required"`
		Competitions string `json:"competitions"`
	}
	if err := c.ShouldBindJSON(&input); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid input"})
		return
	}

	t := strings.ToLower(strings.TrimSpace(input.Type))
	allowed := map[string]bool{"blogs": true, "events": true, "matches": true, "scores": true, "weekly": true}
	if !allowed[t] {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Unknown digest type"})
		return
	}

	// Fetch active subscribers
	var subscribers []models.NewsletterSubscription
	if err := cc.DB.Where("is_active = ?", true).Find(&subscribers).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to load subscribers"})
		return
	}
	if len(subscribers) == 0 {
		c.JSON(http.StatusBadRequest, gin.H{"error": "No active subscribers"})
		return
	}

	// Build digest content once based on selected type
	prefs := services.NewsletterPrefs{
		Email:        "digest@local",
		ContentTypes: []string{},
		Competitions: []string{},
		Frequency:    "daily",
	}
	if t == "weekly" {
		prefs.ContentTypes = []string{"blogs", "events", "matches", "scores"}
		prefs.Frequency = "weekly"
	} else {
		prefs.ContentTypes = []string{t}
	}
	if strings.TrimSpace(input.Competitions) != "" {
		for _, p := range strings.Split(input.Competitions, ",") {
			if v := strings.TrimSpace(p); v != "" {
				prefs.Competitions = append(prefs.Competitions, v)
			}
		}
	}
	subj, html := services.BuildNewsletterDigest("cache/prefetch", prefs)
	if strings.TrimSpace(html) == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "No content for selected digest"})
		return
	}

	// Recipients list
	recipients := make([]string, 0, len(subscribers))
	for _, s := range subscribers {
		if s.Email != "" {
			recipients = append(recipients, s.Email)
		}
	}
	if len(recipients) == 0 {
		c.JSON(http.StatusBadRequest, gin.H{"error": "No valid recipient emails"})
		return
	}

	if subj == "" {
		subj = strings.Title(t) + " digest"
	}

	data := &email.NewsletterData{Subject: subj, Content: html, Recipients: recipients}
	if err := cc.emailService.SendNewsletter(data); err != nil {
		logger.Error("Failed to send digest newsletter: %v", err)
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to send digest newsletter"})
		return
	}

	c.JSON(http.StatusOK, gin.H{"message": "Digest newsletter sent", "recipients": len(recipients), "type": t})
}

// UpdateNewsletterAutomation toggles the automated newsletter scheduler at runtime (non-persistent)
// PATCH /api/v1/admin/newsletter/enable { enabled: boolean }
func (cc *ContactController) UpdateNewsletterAutomation(c *gin.Context) {
	if c.GetString("userRole") != "admin" {
		c.JSON(http.StatusForbidden, gin.H{"error": "Access denied"})
		return
	}
	var input struct {
		Enabled bool `json:"enabled"`
	}
	if err := c.ShouldBindJSON(&input); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid payload"})
		return
	}
	// Persist to Settings (singleton row)
	var s models.Settings
	_ = cc.DB.First(&s).Error // ignore not found
	if s.ID == 0 {
		s = models.Settings{}
	}
	s.NewsletterEnabled = input.Enabled
	if s.ID == 0 {
		if err := cc.DB.Create(&s).Error; err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to persist setting"})
			return
		}
	} else if err := cc.DB.Save(&s).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to persist setting"})
		return
	}
	// Flip the in-memory config flag; effective immediately for next tick
	if config.AppConfig != nil {
		config.AppConfig.NewsletterEnabled = input.Enabled
	}
	c.JSON(http.StatusOK, gin.H{"newsletter_enabled": input.Enabled})
}

// GetNewsletterStatus returns basic scheduling/status info for newsletters (admin only)
// @Summary Newsletter status
// @Description Returns subscriber stats and next approximate run time based on interval
// @Tags admin
// @Security Bearer
// @Produce json
// @Success 200 {object} map[string]interface{}
// @Failure 401 {object} map[string]string
// @Failure 403 {object} map[string]string
// @Router /api/v1/admin/newsletter/status [get]
func (cc *ContactController) GetNewsletterStatus(c *gin.Context) {
	if c.GetString("userRole") != "admin" {
		c.JSON(http.StatusForbidden, gin.H{"error": "Access denied"})
		return
	}

	var total int64
	var active int64
	cc.DB.Model(&models.NewsletterSubscription{}).Count(&total)
	cc.DB.Model(&models.NewsletterSubscription{}).Where("is_active = ?", true).Count(&active)

	var subs []models.NewsletterSubscription
	_ = cc.DB.Where("is_active = ?", true).Limit(20).Find(&subs).Error
	sample := make([]string, 0, len(subs))
	for _, s := range subs {
		if s.Email != "" {
			sample = append(sample, s.Email)
		}
	}

	interval := 24 * time.Hour
	if v := strings.TrimSpace(os.Getenv("NEWSLETTER_INTERVAL_HOURS")); v != "" {
		if d, err := time.ParseDuration(v + "h"); err == nil {
			interval = d
		}
	}
	next := time.Now().Add(interval)

	c.JSON(http.StatusOK, gin.H{
		"total_subscribers":  total,
		"active_subscribers": active,
		"sample_recipients":  sample,
		"interval_minutes":   int(interval.Minutes()),
		"next_approximate":   next,
		"newsletter_enabled": config.AppConfig != nil && config.AppConfig.NewsletterEnabled,
	})
}

// PreviewNewsletter builds a digest preview (subject + html) for admin without sending
// @Summary Preview newsletter digest (admin)
// @Description Returns subject and HTML for a digest newsletter using current cache and optional preferences
// @Tags admin
// @Security Bearer
// @Accept json
// @Produce json
// @Param prefs body map[string]interface{} false "Optional { preferences: { blogs, matches, events, scores, competitions } }"
// @Success 200 {object} map[string]string
// @Failure 401 {object} map[string]string
// @Failure 403 {object} map[string]string
// @Router /api/v1/admin/newsletter/preview [post]
func (cc *ContactController) PreviewNewsletter(c *gin.Context) {
	if c.GetString("userRole") != "admin" {
		c.JSON(http.StatusForbidden, gin.H{"error": "Access denied"})
		return
	}
	var input struct {
		Preferences map[string]interface{} `json:"preferences"`
	}
	_ = c.ShouldBindJSON(&input)

	// Normalize preferences to NewsletterPrefs
	prefs := services.NewsletterPrefs{
		Email:        "preview@local",
		ContentTypes: []string{},
		Competitions: []string{},
		Frequency:    "daily",
	}
	if m := input.Preferences; m != nil {
		if b, ok := m["blogs"].(bool); ok && b {
			prefs.ContentTypes = append(prefs.ContentTypes, "blogs")
		}
		if b, ok := m["events"].(bool); ok && b {
			prefs.ContentTypes = append(prefs.ContentTypes, "events")
		}
		if b, ok := m["matches"].(bool); ok && b {
			prefs.ContentTypes = append(prefs.ContentTypes, "matches")
		}
		if b, ok := m["scores"].(bool); ok && b {
			prefs.ContentTypes = append(prefs.ContentTypes, "scores")
		}
		if cs, ok := m["competitions"].(string); ok && strings.TrimSpace(cs) != "" {
			parts := strings.Split(cs, ",")
			for _, p := range parts {
				if v := strings.TrimSpace(p); v != "" {
					prefs.Competitions = append(prefs.Competitions, v)
				}
			}
		}
	}

	cacheDir := "cache/prefetch"
	subj, html := services.BuildNewsletterDigest(cacheDir, prefs)
	c.JSON(http.StatusOK, gin.H{"subject": subj, "html": html})
}

// GetNewsletterPreferencesByToken returns subscriber preferences using a token (no auth required)
// GET /api/v1/newsletter/preferences?token=...
func (cc *ContactController) GetNewsletterPreferencesByToken(c *gin.Context) {
	token := strings.TrimSpace(c.Query("token"))
	if token == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "token is required"})
		return
	}

	emailStr, err := utils.ParseSubscriberToken(token)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid or expired token"})
		return
	}

	var sub models.NewsletterSubscription
	if err := cc.DB.Where("email = ?", emailStr).First(&sub).Error; err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "Subscription not found"})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"email":       sub.Email,
		"is_active":   sub.IsActive,
		"preferences": sub.Preferences,
	})
}

// SaveNewsletterPreferencesByToken saves subscriber preferences using a token (no auth required)
// POST /api/v1/newsletter/preferences { token, preferences }
func (cc *ContactController) SaveNewsletterPreferencesByToken(c *gin.Context) {
	var input struct {
		Token       string                 `json:"token" binding:"required"`
		Preferences map[string]interface{} `json:"preferences" binding:"required"`
	}
	if err := c.ShouldBindJSON(&input); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid payload"})
		return
	}

	emailStr, err := utils.ParseSubscriberToken(input.Token)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid or expired token"})
		return
	}

	var sub models.NewsletterSubscription
	if err := cc.DB.Where("email = ?", emailStr).First(&sub).Error; err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "Subscription not found"})
		return
	}

	jm := datatypes.JSONMap{}
	for key, raw := range input.Preferences {
		switch v := raw.(type) {
		case bool:
			jm[key] = v
		case string:
			jm[key] = strings.TrimSpace(v)
		case []interface{}:
			compiled := make([]string, 0, len(v))
			for _, item := range v {
				if s, ok := item.(string); ok {
					if trimmed := strings.TrimSpace(s); trimmed != "" {
						compiled = append(compiled, trimmed)
					}
				}
			}
			jm[key] = strings.Join(compiled, ", ")
		case float64, int, int64:
			jm[key] = v
		case nil:
			jm[key] = nil
		default:
			c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("Unsupported preference type for %s", key)})
			return
		}
	}

	if compVal, ok := jm["competitions"]; ok {
		if compStr, ok := compVal.(string); ok {
			comp := strings.TrimSpace(compStr)
			jm["competitions"] = comp
			if comp != "" {
				if catVal, exists := jm["categories"]; !exists {
					jm["categories"] = comp
				} else if catStr, ok := catVal.(string); ok && strings.TrimSpace(catStr) == "" {
					jm["categories"] = comp
				}
			}
		}
	}

	sub.Preferences = jm
	sub.UpdatedAt = time.Now()
	if err := cc.DB.Save(&sub).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save preferences"})
		return
	}

	c.JSON(http.StatusOK, gin.H{"message": "Preferences saved"})
}

// UnsubscribeByToken disables newsletter using a token (no auth required)
// POST /api/v1/newsletter/unsubscribe-token { token }
func (cc *ContactController) UnsubscribeByToken(c *gin.Context) {
	var input struct {
		Token string `json:"token" binding:"required"`
	}
	if err := c.ShouldBindJSON(&input); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid payload"})
		return
	}
	emailStr, err := utils.ParseSubscriberToken(input.Token)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid or expired token"})
		return
	}
	if err := cc.DB.Model(&models.NewsletterSubscription{}).Where("email = ?", emailStr).Update("is_active", false).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to unsubscribe"})
		return
	}
	c.JSON(http.StatusOK, gin.H{"message": "You have been unsubscribed"})
}

// DeleteNewsletterSubscriber deletes a newsletter subscriber (admin only)
// @Summary Delete newsletter subscriber
// @Description Deletes a newsletter subscriber by ID (admin only)
// @Tags admin
// @Security Bearer
// @Produce json
// @Param id path int true "Subscriber ID"
// @Success 200 {object} map[string]string
// @Failure 400 {object} map[string]string
// @Failure 401 {object} map[string]string
// @Failure 403 {object} map[string]string
// @Failure 404 {object} map[string]string
// @Router /api/v1/admin/newsletter/subscribers/{id} [delete]
func (cc *ContactController) DeleteNewsletterSubscriber(c *gin.Context) {
	if c.GetString("userRole") != "admin" {
		c.JSON(http.StatusForbidden, gin.H{"error": "Access denied"})
		return
	}

	id, err := strconv.Atoi(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid subscriber ID"})
		return
	}

	result := cc.DB.Delete(&models.NewsletterSubscription{}, id)
	if result.Error != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to delete subscriber"})
		return
	}
	if result.RowsAffected == 0 {
		c.JSON(http.StatusNotFound, gin.H{"error": "Subscriber not found"})
		return
	}
	c.JSON(http.StatusOK, gin.H{"message": "Subscriber deleted successfully"})
}

// UpdateNewsletterSubscriberStatus toggles a subscriber's active status (admin only)
// @Summary Update newsletter subscriber status
// @Description Updates the is_active status of a newsletter subscriber (admin only)
// @Tags admin
// @Security Bearer
// @Accept json
// @Produce json
// @Param id path int true "Subscriber ID"
// @Param input body map[string]bool true "{ is_active: boolean }"
// @Success 200 {object} models.NewsletterSubscription
// @Failure 400 {object} map[string]string
// @Failure 401 {object} map[string]string
// @Failure 403 {object} map[string]string
// @Failure 404 {object} map[string]string
// @Router /api/v1/admin/newsletter/subscribers/{id}/status [patch]
func (cc *ContactController) UpdateNewsletterSubscriberStatus(c *gin.Context) {
	if c.GetString("userRole") != "admin" {
		c.JSON(http.StatusForbidden, gin.H{"error": "Access denied"})
		return
	}

	id, err := strconv.Atoi(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid subscriber ID"})
		return
	}

	var input struct {
		IsActive bool `json:"is_active" binding:"required"`
	}
	if err := c.ShouldBindJSON(&input); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body"})
		return
	}

	var sub models.NewsletterSubscription
	if err := cc.DB.First(&sub, id).Error; err != nil {
		if err == gorm.ErrRecordNotFound {
			c.JSON(http.StatusNotFound, gin.H{"error": "Subscriber not found"})
		} else {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch subscriber"})
		}
		return
	}

	sub.IsActive = input.IsActive
	sub.UpdatedAt = time.Now()
	if err := cc.DB.Save(&sub).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update subscriber"})
		return
	}

	c.JSON(http.StatusOK, sub)
}

// UpdateNewsletterSubscriberPreferences updates subscriber preferences (admin only)
// @Summary Update newsletter subscriber preferences
// @Description Updates the preferences JSON for a subscriber (admin only)
// @Tags admin
// @Security Bearer
// @Accept json
// @Produce json
// @Param id path int true "Subscriber ID"
// @Param input body map[string]bool true "Preferences map"
// @Success 200 {object} models.NewsletterSubscription
// @Failure 400 {object} map[string]string
// @Failure 401 {object} map[string]string
// @Failure 403 {object} map[string]string
// @Failure 404 {object} map[string]string
// @Router /api/v1/admin/newsletter/subscribers/{id}/preferences [patch]
func (cc *ContactController) UpdateNewsletterSubscriberPreferences(c *gin.Context) {
	if c.GetString("userRole") != "admin" {
		c.JSON(http.StatusForbidden, gin.H{"error": "Access denied"})
		return
	}

	id, err := strconv.Atoi(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid subscriber ID"})
		return
	}

	var prefs map[string]bool
	if err := c.ShouldBindJSON(&prefs); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid preferences payload"})
		return
	}

	var sub models.NewsletterSubscription
	if err := cc.DB.First(&sub, id).Error; err != nil {
		if err == gorm.ErrRecordNotFound {
			c.JSON(http.StatusNotFound, gin.H{"error": "Subscriber not found"})
		} else {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch subscriber"})
		}
		return
	}

	// convert map[string]bool to datatypes.JSONMap
	jm := datatypes.JSONMap{}
	for k, v := range prefs {
		jm[k] = v
	}
	sub.Preferences = jm
	sub.UpdatedAt = time.Now()
	if err := cc.DB.Save(&sub).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update preferences"})
		return
	}

	c.JSON(http.StatusOK, sub)
}

// SendNewsletterTest sends a test newsletter email to a single recipient (admin only)
// @Summary Send test newsletter email
// @Description Sends a test newsletter email to a single recipient (admin only)
// @Tags admin
// @Security Bearer
// @Accept json
// @Produce json
// @Param input body map[string]string false "Optional {email} to send test to"
// @Success 200 {object} map[string]string
// @Failure 400 {object} map[string]string
// @Failure 401 {object} map[string]string
// @Failure 403 {object} map[string]string
// @Router /api/v1/admin/newsletter/test [post]
func (cc *ContactController) SendNewsletterTest(c *gin.Context) {
	if c.GetString("userRole") != "admin" {
		c.JSON(http.StatusForbidden, gin.H{"error": "Access denied"})
		return
	}

	var input struct {
		Email  string   `json:"email"`
		Emails []string `json:"emails"`
		Type   string   `json:"type"`
	}
	_ = c.ShouldBindJSON(&input)

	// Resolve recipients (emails > email > admin)
	recipients := make([]string, 0)
	if len(input.Emails) > 0 {
		for _, e := range input.Emails {
			if v := strings.TrimSpace(e); v != "" {
				recipients = append(recipients, v)
			}
		}
	}
	if len(recipients) == 0 {
		if v := strings.TrimSpace(input.Email); v != "" {
			recipients = append(recipients, v)
		}
	}
	if len(recipients) == 0 {
		if v := strings.TrimSpace(config.AppConfig.AdminEmail); v != "" {
			recipients = append(recipients, v)
		}
	}
	if len(recipients) == 0 {
		c.JSON(http.StatusBadRequest, gin.H{"error": "No recipient email provided"})
		return
	}

	t := strings.ToLower(strings.TrimSpace(input.Type))
	if t == "" {
		t = "newsletter"
	}

	logger.Info("[SendNewsletterTest] type=%s recipients=%v", t, recipients)

	switch t {
	case "newsletter":
		testHTML := `<p>Toto je testovací newsletter z Fotbal Club. Nastavení SMTP funguje.</p>`
		data := &email.NewsletterData{Subject: "Test newsletter", Content: testHTML, Recipients: recipients}
		logger.Debug("[SendNewsletterTest] invoking emailService.SendNewsletter for %d recipient(s)", len(recipients))
		if err := cc.emailService.SendNewsletter(data); err != nil {
			logger.Error("Failed to send test newsletter: %v", err)
			if config.AppConfig != nil && config.AppConfig.AppEnv != "production" {
				c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to send test newsletter", "details": err.Error()})
			} else {
				c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to send test newsletter"})
			}
			return
		}
	case "welcome":
		for _, r := range recipients {
			w := &email.NewsletterWelcomeData{Email: r, UnsubscribeLink: ""}
			if err := cc.emailService.SendNewsletterWelcome(w); err != nil {
				logger.Error("Failed to send welcome test to %s: %v", r, err)
			}
		}
	case "welcome_back":
		for _, r := range recipients {
			w := &email.NewsletterWelcomeBackData{Email: r}
			if err := cc.emailService.SendNewsletterWelcomeBack(w); err != nil {
				logger.Error("Failed to send welcome back test to %s: %v", r, err)
			}
		}
	case "setup":
		// Test subscription setup email with token
		for _, r := range recipients {
			token, tErr := utils.GenerateSubscriberToken(r, 60*24)
			if tErr != nil {
				logger.Error("Failed to generate token for setup test: %v", tErr)
				continue
			}
			baseFE := strings.TrimSuffix(config.AppConfig.FrontendBaseURL, "/")
			setupURL := baseFE + "/newsletter/setup?token=" + url.QueryEscape(token)
			setupEmail := &email.EmailData{
				Subject:  "Test: Nastavte svůj newsletter",
				To:       []string{r},
				Template: "newsletter_setup",
				Data:     struct{ SetupURL string }{SetupURL: setupURL},
			}
			if err := cc.emailService.SendEmail(setupEmail); err != nil {
				logger.Error("Failed to send setup test to %s: %v", r, err)
			}
		}
	case "match_reminder_48h":
		// Test 48h match reminder
		testHTML := `
<div style="max-width: 600px; margin: 0 auto; font-family: Arial, sans-serif;">
	<h2 style="color: #1e3a8a; margin-bottom: 20px;">Připomínáme nadcházející zápas:</h2>
	<div style="border-left: 4px solid #38a169; padding: 20px; background: #f0fff4; margin: 20px 0;">
		<h3 style="margin: 0 0 10px 0; color: #1e3a8a; font-size: 24px;">FC Test vs SK Example</h3>
		<p style="color: #276749; margin: 5px 0;"><strong>Datum:</strong> 2025-10-02</p>
		<p style="color: #276749; margin: 5px 0;"><strong>Čas:</strong> 17:00</p>
		<p style="color: #276749; margin: 5px 0;"><strong>Soutěž:</strong> MFS A</p>
		<p style="color: #276749; margin: 5px 0;"><strong>Místo:</strong> Sportovní areál Test</p>
	</div>
	<p style="color: #4a5568; margin-top: 20px;">Zápas začíná za 48 hodin. Nezapomeňte!</p>
</div>`
		data := &email.NewsletterData{Subject: "Test: Nadcházející zápas za 48 hodin", Content: testHTML, Recipients: recipients}
		if err := cc.emailService.SendNewsletter(data); err != nil {
			logger.Error("Failed to send match reminder test: %v", err)
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to send test"})
			return
		}
	case "match_reminder_today":
		// Test day-of match reminder
		testHTML := `
<div style="max-width: 600px; margin: 0 auto; font-family: Arial, sans-serif;">
	<h2 style="color: #1e3a8a; margin-bottom: 20px;">Zápas je dnes!</h2>
	<div style="border-left: 4px solid #38a169; padding: 20px; background: #f0fff4; margin: 20px 0;">
		<h3 style="margin: 0 0 10px 0; color: #1e3a8a; font-size: 24px;">FC Test vs SK Example</h3>
		<p style="color: #276749; margin: 5px 0;"><strong>Datum:</strong> Dnes</p>
		<p style="color: #276749; margin: 5px 0;"><strong>Čas:</strong> 17:00</p>
		<p style="color: #276749; margin: 5px 0;"><strong>Soutěž:</strong> MFS A</p>
		<p style="color: #276749; margin: 5px 0;"><strong>Místo:</strong> Sportovní areál Test</p>
	</div>
	<p style="color: #4a5568; margin-top: 20px;">Přijďte fandit!</p>
</div>`
		data := &email.NewsletterData{Subject: "Test: Zápas dnes", Content: testHTML, Recipients: recipients}
		if err := cc.emailService.SendNewsletter(data); err != nil {
			logger.Error("Failed to send match today test: %v", err)
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to send test"})
			return
		}
	case "blog_notification":
		// Test blog release notification
		testHTML := `
<div style="max-width: 600px; margin: 0 auto; font-family: Arial, sans-serif;">
	<h2 style="color: #1e3a8a; margin-bottom: 20px;">Nový článek na webu</h2>
	<div style="border-left: 4px solid #2563eb; padding: 20px; background: #f8fafc; margin: 20px 0;">
		<h3 style="margin: 0 0 15px 0; color: #1e3a8a;">Testovací článek: Zajímavosti ze sezóny</h3>
		<p style="color: #4a5568; line-height: 1.6; margin: 0 0 15px 0;">Toto je ukázkový výňatek z nového článku na našem webu. Přečtěte si celý příběh a dozvíte se více zajímavostí ze sezóny.</p>
		<a href="https://example.com/news/test" style="display: inline-block; padding: 12px 24px; background: #2563eb; color: white; text-decoration: none; border-radius: 6px; font-weight: 600;">Číst článek</a>
	</div>
</div>`
		data := &email.NewsletterData{Subject: "Test: Nový článek - Zajímavosti ze sezóny", Content: testHTML, Recipients: recipients}
		if err := cc.emailService.SendNewsletter(data); err != nil {
			logger.Error("Failed to send blog notification test: %v", err)
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to send test"})
			return
		}
	case "match_result":
		// Test match result notification
		testHTML := `
<div style="max-width: 600px; margin: 0 auto; font-family: Arial, sans-serif;">
	<h2 style="color: #1e3a8a; margin-bottom: 20px;">Výsledek zápasu</h2>
	<div style="border-left: 4px solid #d69e2e; padding: 20px; background: #fffbeb; margin: 20px 0;">
		<h3 style="margin: 0 0 10px 0; color: #1e3a8a; font-size: 24px;">FC Test <span style="color: #d69e2e;">3:2</span> SK Example</h3>
		<p style="color: #975a16; margin: 5px 0;"><strong>Datum:</strong> 2025-09-30</p>
		<p style="color: #975a16; margin: 5px 0;"><strong>Soutěž:</strong> MFS A</p>
		<p style="color: #975a16; margin: 10px 0 0 0;">Gratulujeme týmu k vítězství!</p>
	</div>
</div>`
		data := &email.NewsletterData{Subject: "Test: Výsledek - FC Test 3:2 SK Example", Content: testHTML, Recipients: recipients}
		if err := cc.emailService.SendNewsletter(data); err != nil {
			logger.Error("Failed to send match result test: %v", err)
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to send test"})
			return
		}
	// Predefined digest test types mapped to content sections
	case "blogs", "events", "matches", "scores", "weekly":
		prefs := services.NewsletterPrefs{
			Email:        recipients[0],
			ContentTypes: []string{},
			Competitions: []string{},
			Frequency:    "daily",
		}
		if t == "weekly" {
			prefs.ContentTypes = []string{"blogs", "events", "matches", "scores"}
			prefs.Frequency = "weekly"
		} else {
			prefs.ContentTypes = []string{t}
		}
		cacheDir := "cache/prefetch"
		subj, html := services.BuildNewsletterDigest(cacheDir, prefs)
		if subj == "" {
			subj = "Test digest"
		}
		if html == "" {
			html = "<p>Momentálně žádný obsah pro zvolený typ.</p>"
		}
		data := &email.NewsletterData{Subject: subj, Content: html, Recipients: recipients}
		if err := cc.emailService.SendNewsletter(data); err != nil {
			logger.Error("Failed to send digest test: %v", err)
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to send digest test"})
			return
		}
	default:
		c.JSON(http.StatusBadRequest, gin.H{"error": "Unknown test type"})
		return
	}

	c.JSON(http.StatusOK, gin.H{"message": "Test email(s) sent", "recipients": recipients, "type": t})
}

func NewContactController(db *gorm.DB, emailService email.EmailService) *ContactController {
	return &ContactController{
		DB:           db,
		emailService: emailService,
	}
}

type ContactFormRequest struct {
	Name    string `json:"name" binding:"required"`
	Email   string `json:"email" binding:"required,email"`
	Subject string `json:"subject" binding:"required"`
	Message string `json:"message" binding:"required"`
	Source  string `json:"source"` // e.g., "contact", "sponsor"
}

// SubmitContactForm handles contact form submissions
// @Summary Submit contact form
// @Description Handles contact form submissions and sends an email notification
// @Tags contact
// @Accept json
// @Produce json
// @Param input body ContactFormRequest true "Contact form data"
// @Success 200 {object} map[string]string
// @Failure 400 {object} map[string]string
// @Router /api/v1/contact [post]
func (cc *ContactController) SubmitContactForm(c *gin.Context) {
	var input ContactFormRequest
	if err := c.ShouldBindJSON(&input); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	// Normalize source field
	source := strings.TrimSpace(input.Source)
	if source == "" {
		source = "contact"
	}

	// Save to database
	contactMessage := models.ContactMessage{
		Name:      input.Name,
		Email:     input.Email,
		Subject:   input.Subject,
		Message:   input.Message,
		Source:    source,
		IPAddress: c.ClientIP(),
		UserAgent: c.Request.UserAgent(),
		IsRead:    false,
	}

	if err := cc.DB.Create(&contactMessage).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save contact message"})
		return
	}

	// Send email notification asynchronously to prevent frontend timeout
	go func() {
		emailData := &email.ContactFormData{
			Name:      input.Name,
			Email:     input.Email,
			Subject:   input.Subject,
			Message:   input.Message,
			IPAddress: c.ClientIP(),
			UserAgent: c.Request.UserAgent(),
		}

		if err := cc.emailService.SendContactForm(emailData); err != nil {
			logger.Error("Failed to send contact form email: %v", err)
		}
	}()

	c.JSON(http.StatusOK, gin.H{"message": "Your message has been sent successfully"})
}

type NewsletterSubscriptionRequest struct {
	Email       string          `json:"email" binding:"required,email"`
	Preferences map[string]bool `json:"preferences"`
}

// SubscribeToNewsletter handles newsletter subscriptions
// @Summary Subscribe to newsletter
// @Description Handles newsletter subscription requests
// @Tags newsletter
// @Accept json
// @Produce json
// @Param input body NewsletterSubscriptionRequest true "Subscription data"
// @Success 200 {object} map[string]string
// @Failure 400 {object} map[string]string
// @Router /api/v1/newsletter/subscribe [post]
func (cc *ContactController) SubscribeToNewsletter(c *gin.Context) {
	var input NewsletterSubscriptionRequest
	if err := c.ShouldBindJSON(&input); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	// Check if email already exists
	var subscription models.NewsletterSubscription
	result := cc.DB.Where("email = ?", input.Email).First(&subscription)

	if result.Error == nil {
		if !subscription.IsActive {
			// Reactivate existing subscription
			subscription.IsActive = true
			subscription.UpdatedAt = time.Now()
			// Update preferences if provided (convert to JSONMap)
			if input.Preferences != nil {
				jm := datatypes.JSONMap{}
				for k, v := range input.Preferences {
					jm[k] = v
				}
				subscription.Preferences = jm
			}
			if err := cc.DB.Save(&subscription).Error; err != nil {
				c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update subscription"})
				return
			}

			// Send welcome back email in a goroutine
			go func(sub models.NewsletterSubscription) {
				manageURL := ""
				unsubscribeURL := ""
				token, tErr := utils.GenerateSubscriberToken(sub.Email, 60*24)
				if tErr != nil {
					logger.Error("Failed to generate subscriber token: %v", tErr)
				} else {
					baseFE := strings.TrimSuffix(config.AppConfig.FrontendBaseURL, "/")
					if baseFE != "" {
						link := baseFE + "/newsletter/preferences?token=" + url.QueryEscape(token)
						manageURL = link
						unsubscribeURL = link
					}
				}

				emailData := &email.NewsletterWelcomeBackData{
					Email:           sub.Email,
					ManageURL:       manageURL,
					UnsubscribeURL:  unsubscribeURL,
				}
				if err := cc.emailService.SendNewsletterWelcomeBack(emailData); err != nil {
					logger.Error("Failed to send welcome back email: %v", err)
				}
			}(subscription)

			c.JSON(http.StatusOK, gin.H{"message": "Welcome back! You have been resubscribed to our newsletter."})
			return
		}

		c.JSON(http.StatusOK, gin.H{"message": "You are already subscribed to our newsletter"})
		return
	}

	// Create new subscription. Default: enable everything if preferences omitted
	prefs := input.Preferences
	if prefs == nil {
		prefs = map[string]bool{"weekly": true, "matches": true, "blogs": true, "events": true}
	}
	// convert to datatypes.JSONMap
	jm := datatypes.JSONMap{}
	for k, v := range prefs {
		jm[k] = v
	}
	subscription = models.NewsletterSubscription{
		Email:       input.Email,
		IsActive:    true,
		Preferences: jm,
		CreatedAt:   time.Now(),
		UpdatedAt:   time.Now(),
	}

	if err := cc.DB.Create(&subscription).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to subscribe to newsletter"})
		return
	}

	// Send setup email (link with token) AND welcome introduction email in goroutines
	go func() {
		// Generate token and build setup + unsubscribe URLs
		token, tErr := utils.GenerateSubscriberToken(subscription.Email, 60*24) // 1 day
		if tErr != nil {
			logger.Error("Failed to generate subscriber token: %v", tErr)
			return
		}
		baseFE := strings.TrimSuffix(config.AppConfig.FrontendBaseURL, "/")
		setupURL := baseFE + "/newsletter/setup?token=" + url.QueryEscape(token)
		unsubscribeURL := baseFE + "/newsletter/preferences?token=" + url.QueryEscape(token)

		// 1) Setup email
		setupEmail := &email.EmailData{
			Subject:  "Nastavte svůj newsletter",
			To:       []string{subscription.Email},
			Template: "newsletter_setup",
			Data:     struct{ SetupURL string }{SetupURL: setupURL},
		}
		if err := cc.emailService.SendEmail(setupEmail); err != nil {
			logger.Error("Failed to send setup email: %v", err)
		}

		// 2) Welcome introduction email (includes unsubscribe/manage link)
		welcome := &email.NewsletterWelcomeData{
			Email:           subscription.Email,
			UnsubscribeLink: unsubscribeURL,
		}
		if err := cc.emailService.SendNewsletterWelcome(welcome); err != nil {
			logger.Error("Failed to send welcome email: %v", err)
		}
	}()

	c.JSON(http.StatusOK, gin.H{"message": "Thank you for subscribing to our newsletter! Please check your email to confirm your subscription."})
}

// SetupNewsletterPreferences accepts a subscriber token and preferences to save choices
// ... (rest of the code remains the same)
// @Summary Setup newsletter preferences
// @Description Accepts token and preferences to save subscriber choices
// @Accept json
// @Produce json
// @Param input body map[string]interface{} true "{ token: string, preferences: { .. } }"
// @Success 200 {object} map[string]string
// @Failure 400 {object} map[string]string
// @Router /api/v1/newsletter/setup [post]
func (cc *ContactController) SetupNewsletterPreferences(c *gin.Context) {
	var input struct {
		Token       string          `json:"token" binding:"required"`
		Preferences map[string]bool `json:"preferences" binding:"required"`
	}
	if err := c.ShouldBindJSON(&input); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid payload"})
		return
	}

	emailStr, err := utils.ParseSubscriberToken(input.Token)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid or expired token"})
		return
	}

	var sub models.NewsletterSubscription
	if err := cc.DB.Where("email = ?", emailStr).First(&sub).Error; err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "Subscription not found"})
		return
	}

	// convert map[string]bool to datatypes.JSONMap
	jm := datatypes.JSONMap{}
	for k, v := range input.Preferences {
		jm[k] = v
	}
	sub.Preferences = jm
	sub.UpdatedAt = time.Now()
	if err := cc.DB.Save(&sub).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save preferences"})
		return
	}

	c.JSON(http.StatusOK, gin.H{"message": "Preferences saved"})
}

// GetContactMessages returns a list of contact messages (admin only)
// @Summary Get contact messages
// @Description Returns a paginated list of contact messages (admin only)
// @Tags admin
// @Security Bearer
// @Produce json
// @Param page query int false "Page number" default(1)
// @Param limit query int false "Items per page" default(10)
// @Success 200 {object} map[string]interface{}
// @Failure 401 {object} map[string]string
// @Failure 403 {object} map[string]string
// @Router /api/v1/admin/contact-messages [get]
func (cc *ContactController) GetContactMessages(c *gin.Context) {
	// Check if user is admin
	if c.GetString("userRole") != "admin" {
		c.JSON(http.StatusForbidden, gin.H{"error": "Access denied"})
		return
	}

	// Get pagination parameters
	page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
	limit, _ := strconv.Atoi(c.DefaultQuery("limit", "10"))
	offset := (page - 1) * limit

	var messages []models.ContactMessage
	var total int64

	// Get total count
	if err := cc.DB.Model(&models.ContactMessage{}).Count(&total).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch messages"})
		return
	}

	// Get paginated messages
	if err := cc.DB.Offset(offset).Limit(limit).Order("created_at DESC").Find(&messages).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch messages"})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"data": messages,
		"pagination": gin.H{
			"total":    total,
			"page":     page,
			"limit":    limit,
			"pages":    (int(total) + limit - 1) / limit,
			"has_more": offset+limit < int(total),
		},
	})
}

// MarkMessageAsRead marks a contact message as read (admin only)
// @Summary Mark message as read
// @Description Marks a contact message as read (admin only)
// @Tags admin
// @Security Bearer
// @Produce json
// @Param id path int true "Message ID"
// @Success 200 {object} map[string]string
// @Failure 400 {object} map[string]string
// @Failure 401 {object} map[string]string
// @Failure 403 {object} map[string]string
// @Failure 404 {object} map[string]string
// @Router /api/v1/admin/contact-messages/{id}/read [patch]
func (cc *ContactController) MarkMessageAsRead(c *gin.Context) {
	// Check if user is admin
	if c.GetString("userRole") != "admin" {
		c.JSON(http.StatusForbidden, gin.H{"error": "Access denied"})
		return
	}

	var message models.ContactMessage
	if err := cc.DB.First(&message, c.Param("id")).Error; err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "Message not found"})
		return
	}

	message.IsRead = true
	message.ReadAt = time.Now()

	if err := cc.DB.Save(&message).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update message"})
		return
	}

	c.JSON(http.StatusOK, gin.H{"message": "Message marked as read"})
}

// GetNewsletterSubscribers returns a list of newsletter subscribers (admin only)
// @Summary Get newsletter subscribers
// @Description Returns a list of all newsletter subscribers (admin only)
// @Tags admin
// @Security Bearer
// @Produce json
// @Success 200 {object} []models.NewsletterSubscription
// @Failure 401 {object} map[string]string
// @Failure 403 {object} map[string]string
// @Router /api/v1/admin/newsletter/subscribers [get]
func (cc *ContactController) GetNewsletterSubscribers(c *gin.Context) {
	if c.GetString("userRole") != "admin" {
		c.JSON(http.StatusForbidden, gin.H{"error": "Access denied"})
		return
	}

	var subscribers []models.NewsletterSubscription
	if err := cc.DB.Find(&subscribers).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch subscribers"})
		return
	}

	c.JSON(http.StatusOK, subscribers)
}

// SendNewsletter sends a newsletter to all active subscribers (admin only)
// @Summary Send newsletter
// @Description Sends a newsletter to all active subscribers (admin only)
// @Tags admin
// @Security Bearer
// @Accept json
// @Produce json
// @Param input body map[string]string true "Newsletter content (subject and body)"
// @Success 200 {object} map[string]string
// @Failure 400 {object} map[string]string
// @Failure 401 {object} map[string]string
// @Failure 403 {object} map[string]string
// @Router /api/v1/admin/newsletter/send [post]
func (cc *ContactController) SendNewsletter(c *gin.Context) {
	if c.GetString("userRole") != "admin" {
		c.JSON(http.StatusForbidden, gin.H{"error": "Access denied"})
		return
	}

	var input struct {
		Subject string `json:"subject" binding:"required"`
		Body    string `json:"body"`
		Content string `json:"content"`
	}

	if err := c.ShouldBindJSON(&input); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid input"})
		return
	}

	// Support both 'body' (backend) and 'content' (frontend variant)
	bodyText := strings.TrimSpace(input.Body)
	if bodyText == "" {
		bodyText = strings.TrimSpace(input.Content)
	}
	if bodyText == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Newsletter body/content is required"})
		return
	}

	// Fetch active subscribers
	var subscribers []models.NewsletterSubscription
	if err := cc.DB.Where("is_active = ?", true).Find(&subscribers).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to load subscribers"})
		return
	}

	if len(subscribers) == 0 {
		c.JSON(http.StatusBadRequest, gin.H{"error": "No active subscribers"})
		return
	}

	// Build recipient list
	recipients := make([]string, 0, len(subscribers))
	for _, s := range subscribers {
		if s.Email != "" {
			recipients = append(recipients, s.Email)
		}
	}

	if len(recipients) == 0 {
		c.JSON(http.StatusBadRequest, gin.H{"error": "No valid recipient emails"})
		return
	}

	logger.Info("[SendNewsletter] sending to %d active subscribers", len(recipients))

	// Send via email service
	data := &email.NewsletterData{
		Subject:    input.Subject,
		Content:    bodyText,
		Recipients: recipients,
	}

	if err := cc.emailService.SendNewsletter(data); err != nil {
		logger.Error("Failed to send newsletter: %v", err)
		if config.AppConfig != nil && config.AppConfig.AppEnv != "production" {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to send newsletter", "details": err.Error()})
		} else {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to send newsletter"})
		}
		return
	}

	c.JSON(http.StatusOK, gin.H{"message": "Newsletter sent successfully", "recipients": len(recipients)})
}

// UnsubscribeFromNewsletter handles newsletter unsubscription
// @Summary Unsubscribe from newsletter
// @Description Handles newsletter unsubscription requests
// @Tags newsletter
// @Produce json
// @Param email path string true "Subscriber email"
// @Success 200 {object} map[string]string
// @Failure 400 {object} map[string]string
// @Router /api/v1/newsletter/unsubscribe/{email} [post]
func (cc *ContactController) UnsubscribeFromNewsletter(c *gin.Context) {
	email := c.Param("email")
	if email == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Email is required"})
		return
	}

	// Set subscription as inactive instead of deleting
	result := cc.DB.Model(&models.NewsletterSubscription{}).Where("email = ?", email).Update("is_active", false)
	if result.Error != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to unsubscribe"})
		return
	}

	if result.RowsAffected == 0 {
		c.JSON(http.StatusNotFound, gin.H{"error": "Subscription not found"})
		return
	}

	c.JSON(http.StatusOK, gin.H{"message": "Successfully unsubscribed from newsletter"})
}

// GetContactMessage returns a single contact message by ID (admin only)
// @Summary Get contact message
// @Description Returns a single contact message by ID (admin only)
// @Tags admin
// @Security Bearer
// @Produce json
// @Param id path int true "Message ID"
// @Success 200 {object} models.ContactMessage
// @Failure 400 {object} map[string]string
// @Failure 401 {object} map[string]string
// @Failure 403 {object} map[string]string
// @Failure 404 {object} map[string]string
// @Router /api/v1/admin/contact-messages/{id} [get]
func (cc *ContactController) GetContactMessage(c *gin.Context) {
	id, err := strconv.Atoi(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid message ID"})
		return
	}

	var message models.ContactMessage
	if err := cc.DB.First(&message, id).Error; err != nil {
		if err == gorm.ErrRecordNotFound {
			c.JSON(http.StatusNotFound, gin.H{"error": "Message not found"})
		} else {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch message"})
		}
		return
	}

	c.JSON(http.StatusOK, message)
}

// DeleteContactMessage deletes a contact message (admin only)
// @Summary Delete contact message
// @Description Deletes a contact message by ID (admin only)
// @Tags admin
// @Security Bearer
// @Produce json
// @Param id path int true "Message ID"
// @Success 200 {object} map[string]string
// @Failure 400 {object} map[string]string
// @Failure 401 {object} map[string]string
// @Failure 403 {object} map[string]string
// @Router /api/v1/admin/contact-messages/{id} [delete]
func (cc *ContactController) DeleteContactMessage(c *gin.Context) {
	id, err := strconv.Atoi(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid message ID"})
		return
	}

	result := cc.DB.Delete(&models.ContactMessage{}, id)
	if result.Error != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to delete message"})
		return
	}

	if result.RowsAffected == 0 {
		c.JSON(http.StatusNotFound, gin.H{"error": "Message not found"})
		return
	}

	c.JSON(http.StatusOK, gin.H{"message": "Message deleted successfully"})
}

// DeleteContactMessages deletes multiple contact messages (admin only)
// @Summary Delete multiple contact messages
// @Description Deletes multiple contact messages by their IDs (admin only)
// @Tags admin
// @Security Bearer
// @Accept json
// @Produce json
// @Param ids body []int true "Array of message IDs to delete"
// @Success 200 {object} map[string]string
// @Failure 400 {object} map[string]string
// @Failure 401 {object} map[string]string
// @Failure 403 {object} map[string]string
// @Router /api/v1/admin/contact-messages [delete]
func (cc *ContactController) DeleteContactMessages(c *gin.Context) {
	var ids []int
	if err := c.ShouldBindJSON(&ids); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body"})
		return
	}

	if len(ids) == 0 {
		c.JSON(http.StatusBadRequest, gin.H{"error": "No message IDs provided"})
		return
	}

	result := cc.DB.Delete(&models.ContactMessage{}, ids)
	if result.Error != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to delete messages"})
		return
	}

	if result.RowsAffected == 0 {
		c.JSON(http.StatusNotFound, gin.H{"error": "No messages found with the provided IDs"})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"message": fmt.Sprintf("Successfully deleted %d message(s)", result.RowsAffected),
	})
}

// ForwardContactMessage forwards a contact message to a specified email (admin only)
// @Summary Forward contact message
// @Description Forwards a contact message to a specified email address (admin only)
// @Tags admin
// @Security Bearer
// @Accept json
// @Produce json
// @Param id path int true "Message ID"
// @Param input body map[string]string true "{ to_email: string }"
// @Success 200 {object} map[string]string
// @Failure 400 {object} map[string]string
// @Failure 401 {object} map[string]string
// @Failure 403 {object} map[string]string
// @Failure 404 {object} map[string]string
// @Router /api/v1/admin/contact-messages/{id}/forward [post]
func (cc *ContactController) ForwardContactMessage(c *gin.Context) {
	if c.GetString("userRole") != "admin" {
		c.JSON(http.StatusForbidden, gin.H{"error": "Access denied"})
		return
	}

	id, err := strconv.Atoi(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid message ID"})
		return
	}

	var input struct {
		ToEmail string `json:"to_email" binding:"required,email"`
	}
	if err := c.ShouldBindJSON(&input); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Valid email address is required"})
		return
	}

	// Fetch the message
	var message models.ContactMessage
	if err := cc.DB.First(&message, id).Error; err != nil {
		if err == gorm.ErrRecordNotFound {
			c.JSON(http.StatusNotFound, gin.H{"error": "Message not found"})
		} else {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch message"})
		}
		return
	}

	// Prepare email data for forwarding
	forwardData := &email.EmailData{
		Subject: fmt.Sprintf("Fwd: Contact Form - %s", message.Subject),
		To:      []string{input.ToEmail},
		Template: "contact_form",
		Data: struct {
			Name    string
			Email   string
			Subject string
			Message string
			Time    string
			IP      string
			Agent   string
		}{
			Name:    message.Name,
			Email:   message.Email,
			Subject: message.Subject,
			Message: message.Message,
			Time:    message.CreatedAt.Format(time.RFC1123Z),
			IP:      message.IPAddress,
			Agent:   message.UserAgent,
		},
	}

	// Send email asynchronously
	go func() {
		if err := cc.emailService.SendEmail(forwardData); err != nil {
			logger.Error("Failed to forward contact message %d to %s: %v", id, input.ToEmail, err)
		} else {
			logger.Info("Contact message %d forwarded to %s", id, input.ToEmail)
		}
	}()

	c.JSON(http.StatusOK, gin.H{"message": "Message is being forwarded to " + input.ToEmail})
}

// ForwardAllContactMessages forwards all contact messages to a specified email (admin only)
// @Summary Forward all contact messages
// @Description Forwards all contact messages to a specified email address (admin only)
// @Tags admin
// @Security Bearer
// @Accept json
// @Produce json
// @Param input body map[string]string true "{ to_email: string }"
// @Success 200 {object} map[string]string
// @Failure 400 {object} map[string]string
// @Failure 401 {object} map[string]string
// @Failure 403 {object} map[string]string
// @Router /api/v1/admin/contact-messages/forward-all [post]
func (cc *ContactController) ForwardAllContactMessages(c *gin.Context) {
	if c.GetString("userRole") != "admin" {
		c.JSON(http.StatusForbidden, gin.H{"error": "Access denied"})
		return
	}

	var input struct {
		ToEmail string `json:"to_email" binding:"required,email"`
	}
	if err := c.ShouldBindJSON(&input); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Valid email address is required"})
		return
	}

	// Fetch all messages
	var messages []models.ContactMessage
	if err := cc.DB.Order("created_at DESC").Find(&messages).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch messages"})
		return
	}

	if len(messages) == 0 {
		c.JSON(http.StatusBadRequest, gin.H{"error": "No messages to forward"})
		return
	}

	// Forward all messages asynchronously
	go func(msgs []models.ContactMessage, toEmail string) {
		successCount := 0
		for _, message := range msgs {
			forwardData := &email.EmailData{
				Subject: fmt.Sprintf("Fwd: Contact Form - %s", message.Subject),
				To:      []string{toEmail},
				Template: "contact_form",
				Data: struct {
					Name    string
					Email   string
					Subject string
					Message string
					Time    string
					IP      string
					Agent   string
				}{
					Name:    message.Name,
					Email:   message.Email,
					Subject: message.Subject,
					Message: message.Message,
					Time:    message.CreatedAt.Format(time.RFC1123Z),
					IP:      message.IPAddress,
					Agent:   message.UserAgent,
				},
			}

			if err := cc.emailService.SendEmail(forwardData); err != nil {
				logger.Error("Failed to forward contact message %d to %s: %v", message.ID, toEmail, err)
			} else {
				successCount++
			}
		}
		logger.Info("Forwarded %d of %d contact messages to %s", successCount, len(msgs), toEmail)
	}(messages, input.ToEmail)

	c.JSON(http.StatusOK, gin.H{
		"message": fmt.Sprintf("Forwarding %d message(s) to %s", len(messages), input.ToEmail),
		"count":   len(messages),
	})
}
