package controllers

import (
    "encoding/base64"
    "net/http"
    "net/url"
    "strconv"
    "strings"
    "time"

    "fotbal-club/internal/config"
    "fotbal-club/internal/models"
    "fotbal-club/internal/services"

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

// EmailController handles tracking endpoints and basic analytics
type EmailController struct {
    DB *gorm.DB
}

// sendUmamiEmailEvent sends a custom event to Umami if configured.
func sendUmamiEmailEvent(name, urlPath, title string, data map[string]any) {
    cfg := config.AppConfig
    if cfg == nil || cfg.UmamiURL == "" || cfg.UmamiWebsiteID == "" {
        return
    }
    svc := services.NewUmamiService()
    // Best-effort, ignore error
    _ = svc.SendEvent(cfg.UmamiWebsiteID, name, urlPath, title, data, "email")
}

// Admin: events for a specific email log
// GET /api/v1/admin/newsletter/stats/:id/events
func (ec *EmailController) GetEmailEventsForLog(c *gin.Context) {
    if c.GetString("userRole") != "admin" {
        c.JSON(http.StatusForbidden, gin.H{"error": "Access denied"})
        return
    }
    idStr := c.Param("id")
    id, err := strconv.Atoi(idStr)
    if err != nil || id <= 0 {
        c.JSON(http.StatusBadRequest, gin.H{"error": "invalid id"})
        return
    }
    // Verify log exists
    var log models.EmailLog
    if err := ec.DB.First(&log, id).Error; err != nil {
        c.JSON(http.StatusNotFound, gin.H{"error": "email log not found"})
        return
    }
    var events []models.EmailEvent
    if err := ec.DB.Where("email_log_id = ?", log.ID).Order("created_at ASC").Find(&events).Error; err != nil {
        c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to load events"})
        return
    }
    c.JSON(http.StatusOK, gin.H{"data": events})
}

func NewEmailController(db *gorm.DB) *EmailController {
    return &EmailController{DB: db}
}

// 1x1 transparent GIF bytes
var oneByOneGIF = []byte{
    0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x01, 0x00,
    0x01, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
    0xff, 0xff, 0xff, 0x21, 0xf9, 0x04, 0x01, 0x00,
    0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00,
    0x01, 0x00, 0x01, 0x00, 0x00, 0x02, 0x02, 0x44,
    0x01, 0x00, 0x3b,
}

// OpenPixel records an open event and returns a transparent GIF
// GET /api/v1/email/open.gif?m=<log_id>&t=<token>
func (ec *EmailController) OpenPixel(c *gin.Context) {
    idStr := c.Query("m")
    tok := strings.TrimSpace(c.Query("t"))
    if idStr == "" || tok == "" {
        c.Data(http.StatusOK, "image/gif", oneByOneGIF)
        return
    }
    id, _ := strconv.Atoi(idStr)
    var log models.EmailLog
    if err := ec.DB.First(&log, id).Error; err == nil && log.Token == tok {
        meta := models.EmailEvent{EmailLogID: log.ID, EventType: "open", Meta: map[string]any{
            "ua": c.Request.UserAgent(),
            "ip": c.ClientIP(),
        }}
        _ = ec.DB.Create(&meta).Error
        // Send Umami event (non-blocking)
        go sendUmamiEmailEvent("Email Open", "/email/open", "Email Open", map[string]any{
            "recipient": log.RecipientEmail,
            "subject":   log.Subject,
        })
    }
    c.Header("Cache-Control", "no-store, must-revalidate")
    c.Data(http.StatusOK, "image/gif", oneByOneGIF)
}

// ClickRedirect records a click event then redirects to the target URL
// GET /api/v1/email/click?m=<log_id>&t=<token>&u=<encoded_url>
func (ec *EmailController) ClickRedirect(c *gin.Context) {
    idStr := c.Query("m")
    tok := strings.TrimSpace(c.Query("t"))
    target := c.Query("u")
    if target == "" {
        c.JSON(http.StatusBadRequest, gin.H{"error": "missing u"})
        return
    }
    // allow both raw absolute or base64-encoded URLs
    if strings.HasPrefix(target, "http://") || strings.HasPrefix(target, "https://") {
        // ok
    } else {
        if decoded, err := base64.URLEncoding.DecodeString(target); err == nil {
            target = string(decoded)
        }
    }
    // Validate URL
    if u, err := url.Parse(target); err != nil || (u.Scheme != "http" && u.Scheme != "https") {
        c.JSON(http.StatusBadRequest, gin.H{"error": "invalid url"})
        return
    }
    if idStr != "" && tok != "" {
        if id, err := strconv.Atoi(idStr); err == nil {
            var log models.EmailLog
            if err := ec.DB.First(&log, id).Error; err == nil && log.Token == tok {
                meta := models.EmailEvent{EmailLogID: log.ID, EventType: "click", Meta: map[string]any{
                    "url": target,
                    "ua":  c.Request.UserAgent(),
                    "ip":  c.ClientIP(),
                }}
                _ = ec.DB.Create(&meta).Error
                // Send Umami event (non-blocking)
                go sendUmamiEmailEvent("Email Click", "/email/click", "Email Click", map[string]any{
                    "recipient": log.RecipientEmail,
                    "subject":   log.Subject,
                    "url":       target,
                })
            }
        }
    }
    c.Redirect(http.StatusFound, target)
}

// MarkSpam marks an email as spam and (optionally) deactivates the subscriber
// GET /api/v1/email/spam?m=<log_id>&t=<token>
func (ec *EmailController) MarkSpam(c *gin.Context) {
    idStr := c.Query("m")
    tok := strings.TrimSpace(c.Query("t"))
    id, _ := strconv.Atoi(idStr)
    var log models.EmailLog
    if err := ec.DB.First(&log, id).Error; err == nil && log.Token == tok {
        _ = ec.DB.Create(&models.EmailEvent{EmailLogID: log.ID, EventType: "spam", Meta: map[string]any{"at": time.Now().Format(time.RFC3339)}}).Error
        // try to deactivate subscription
        _ = ec.DB.Model(&models.NewsletterSubscription{}).Where("email = ?", log.RecipientEmail).Update("is_active", false).Error
        // Send Umami event (non-blocking)
        go sendUmamiEmailEvent("Email Spam", "/email/spam", "Email Marked Spam", map[string]any{
            "recipient": log.RecipientEmail,
            "subject":   log.Subject,
        })
    }
    c.JSON(http.StatusOK, gin.H{"ok": true})
}

// Unsubscribe marks unsubscribe and deactivates the subscriber
// GET /api/v1/email/unsubscribe?m=<log_id>&t=<token>
func (ec *EmailController) Unsubscribe(c *gin.Context) {
    idStr := c.Query("m")
    tok := strings.TrimSpace(c.Query("t"))
    id, _ := strconv.Atoi(idStr)
    var log models.EmailLog
    if err := ec.DB.First(&log, id).Error; err == nil && log.Token == tok {
        _ = ec.DB.Create(&models.EmailEvent{EmailLogID: log.ID, EventType: "unsubscribe", Meta: map[string]any{"at": time.Now().Format(time.RFC3339)}}).Error
        _ = ec.DB.Model(&models.NewsletterSubscription{}).Where("email = ?", log.RecipientEmail).Update("is_active", false).Error
        // Send Umami event (non-blocking)
        go sendUmamiEmailEvent("Email Unsubscribe", "/email/unsubscribe", "Email Unsubscribe", map[string]any{
            "recipient": log.RecipientEmail,
            "subject":   log.Subject,
        })
    }
    c.JSON(http.StatusOK, gin.H{"ok": true})
}

// Admin: recent email logs with event counts
// GET /api/v1/admin/newsletter/stats/recent
func (ec *EmailController) GetRecentEmailStats(c *gin.Context) {
    if c.GetString("userRole") != "admin" {
        c.JSON(http.StatusForbidden, gin.H{"error": "Access denied"})
        return
    }
    var logs []models.EmailLog
    _ = ec.DB.Order("created_at DESC").Limit(50).Find(&logs).Error
    // aggregate events per log
    type Row struct {
        ID     uint
        Opens  int64
        Clicks int64
        Spam   int64
        Unsubs int64
    }
    rows := map[uint]*Row{}
    var evs []models.EmailEvent
    _ = ec.DB.Where("email_log_id IN ?", func() []uint {
        ids := make([]uint, 0, len(logs))
        for _, l := range logs { ids = append(ids, l.ID) }
        if len(ids) == 0 { ids = []uint{0} }
        return ids
    }()).Find(&evs).Error
    for _, e := range evs {
        r := rows[e.EmailLogID]
        if r == nil { r = &Row{ID: e.EmailLogID}; rows[e.EmailLogID] = r }
        switch strings.ToLower(e.EventType) {
        case "open": r.Opens++
        case "click": r.Clicks++
        case "spam": r.Spam++
        case "unsubscribe": r.Unsubs++
        }
    }
    // build response
    out := make([]gin.H, 0, len(logs))
    for _, l := range logs {
        r := rows[l.ID]
        var opens, clicks, spam, unsubs int64
        if r != nil {
            opens, clicks, spam, unsubs = r.Opens, r.Clicks, r.Spam, r.Unsubs
        }
        out = append(out, gin.H{
            "id": l.ID,
            "created_at": l.CreatedAt,
            "subject": l.Subject,
            "recipient": l.RecipientEmail,
            "type": l.Type,
            "status": l.Status,
            "opens":  opens,
            "clicks": clicks,
            "spam":   spam,
            "unsubs": unsubs,
        })
    }
    c.JSON(http.StatusOK, gin.H{"data": out})
}
