package services

import (
	"encoding/json"
	"fmt"
	"log"
	"net/url"
	"path/filepath"
	"strings"
	"time"

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

	"gorm.io/gorm"
)

// NewsletterAutomation handles all automated newsletter sending
type NewsletterAutomation struct {
	db          *gorm.DB
	emailSvc    email.EmailService
	cacheDir    string
	lastWeekly  time.Time
	lastMatchCheck time.Time
}

// NewNewsletterAutomation creates a new automation service
func NewNewsletterAutomation(db *gorm.DB, emailSvc email.EmailService) *NewsletterAutomation {
	return &NewsletterAutomation{
		db:       db,
		emailSvc: emailSvc,
		cacheDir: filepath.Join("cache", "prefetch"),
	}
}

// Start begins the newsletter automation loop
func (na *NewsletterAutomation) Start() {
	log.Printf("[newsletter-automation] Starting automated newsletter service")
	
	// Run initial check after 1 minute
	time.AfterFunc(1*time.Minute, func() {
		na.RunCycle()
	})
	
	// Then run every 15 minutes
	ticker := time.NewTicker(15 * time.Minute)
	go func() {
		for range ticker.C {
			na.RunCycle()
		}
	}()
}

// RunCycle executes all newsletter checks
func (na *NewsletterAutomation) RunCycle() {
	if !na.isEnabled() {
		log.Printf("[newsletter-automation] Skipped: disabled in settings")
		return
	}
	
	log.Printf("[newsletter-automation] Running cycle...")
	
	// Check for weekly digest
	na.checkWeeklyDigest()
	
	// Check for upcoming matches (reminders)
	na.checkUpcomingMatches()
	
	// Check for finished matches (results)
	na.checkFinishedMatches()
	
	log.Printf("[newsletter-automation] Cycle complete")
}

// SendBlogNotification sends immediate notification when a blog is published
func (na *NewsletterAutomation) SendBlogNotification(article *models.Article) error {
	if !na.isEnabled() {
		return fmt.Errorf("newsletter automation is disabled")
	}
	
	// Check if already sent
	var existing models.BlogNotification
	if err := na.db.Where("article_id = ?", article.ID).First(&existing).Error; err == nil {
		log.Printf("[newsletter-automation] Blog notification already sent for article %d", article.ID)
		return nil
	}
	
	// Get subscribers interested in blogs
	subs := na.getSubscribersForType("blogs", article.CategoryName)
	if len(subs) == 0 {
		log.Printf("[newsletter-automation] No subscribers for blog notifications")
		return nil
	}
	
	// Build email content
	subject := fmt.Sprintf("Nový článek: %s", article.Title)
	baseFE := strings.TrimSuffix(config.AppConfig.FrontendBaseURL, "/")
	articleURL := fmt.Sprintf("%s/news/%s", baseFE, article.Slug)
	
	html := na.buildBlogNotificationHTML(article, articleURL)
	
	// Send to each subscriber
	recipients := make([]string, 0, len(subs))
	for _, sub := range subs {
		recipients = append(recipients, sub.Email)
	}
	
	err := na.sendNewsletterToRecipients(recipients, subject, html, "blog_release")
	if err != nil {
		logger.Error("[newsletter-automation] Failed to send blog notification: %v", err)
		return err
	}
	
	// Record notification
	notif := models.BlogNotification{
		ArticleID:       article.ID,
		SentAt:          time.Now(),
		RecipientsCount: len(recipients),
		CreatedAt:       time.Now(),
	}
	na.db.Create(&notif)
	
	log.Printf("[newsletter-automation] Blog notification sent for article %d to %d recipients", article.ID, len(recipients))
	return nil
}

func (na *NewsletterAutomation) checkWeeklyDigest() {
	var settings models.Settings
	na.db.First(&settings)
	
	if !settings.EnableWeekly {
		return
	}
	
	// Get configured day and hour
	targetDay := strings.ToLower(strings.TrimSpace(settings.NewsletterWeeklyDay))
	if targetDay == "" {
		targetDay = "sun" // Default to Sunday
	}
	targetHour := settings.NewsletterWeeklyHour
	if targetHour < 0 || targetHour > 23 {
		targetHour = 9 // Default to 9 AM
	}
	
	now := time.Now()
	currentDay := strings.ToLower(now.Weekday().String()[:3])
	currentHour := now.Hour()
	
	// Check if it's the right day and hour
	if currentDay != targetDay || currentHour != targetHour {
		return
	}
	
	// Check if already sent today
	if na.lastWeekly.Year() == now.Year() && na.lastWeekly.YearDay() == now.YearDay() {
		return
	}
	
	// Get all subscribers interested in weekly digest
	subs := na.getSubscribersForType("weekly", "")
	if len(subs) == 0 {
		log.Printf("[newsletter-automation] No subscribers for weekly digest")
		return
	}
	
	log.Printf("[newsletter-automation] Sending weekly digest to %d subscribers", len(subs))
	
	// Build weekly content for each subscriber based on their preferences
	for _, sub := range subs {
		prefs := na.parsePreferences(sub)
		subject, html := BuildNewsletterDigest(na.cacheDir, prefs)
		
		if strings.TrimSpace(html) == "" {
			continue
		}
		
		err := na.sendNewsletterToRecipients([]string{sub.Email}, subject, html, "weekly")
		if err != nil {
			logger.Error("[newsletter-automation] Failed to send weekly digest to %s: %v", sub.Email, err)
		}
		
		time.Sleep(200 * time.Millisecond) // Rate limiting
	}
	
	na.lastWeekly = now
	log.Printf("[newsletter-automation] Weekly digest sent")
}

func (na *NewsletterAutomation) checkUpcomingMatches() {
	var settings models.Settings
	na.db.First(&settings)
	
	if !settings.EnableMatchReminders {
		return
	}
	
	leadHours := settings.NewsletterReminderLeadHours
	if leadHours <= 0 {
		leadHours = 48 // Default 2 days
	}
	
	// Load match data from cache
	facr := readJSON(filepath.Join(na.cacheDir, "facr_club_info.json"))
	matches := facrAllMatches(facr)
	
	now := time.Now()
	
	for _, match := range matches {
		matchTime := parseDateTimeISO(match.Date, match.Time)
		if matchTime.IsZero() || matchTime.Before(now) {
			continue
		}
		
		hoursUntil := matchTime.Sub(now).Hours()
		
		// Check for 48h reminder
		if hoursUntil <= float64(leadHours) && hoursUntil > float64(leadHours-1) {
			na.sendMatchReminder(match, "reminder_48h", leadHours)
		}
		
		// Check for day-of reminder (match starts in 0-6 hours)
		if hoursUntil <= 6 && hoursUntil > 0 {
			na.sendMatchReminder(match, "reminder_day", 0)
		}
	}
}

func (na *NewsletterAutomation) sendMatchReminder(match Match, notifType string, hoursBeforeText int) {
	// Check if already sent
	var existing models.MatchNotification
	matchKey := fmt.Sprintf("%s-%s-%s", match.Date, match.Home, match.Away)
	if err := na.db.Where("match_id = ? AND notification_type = ?", matchKey, notifType).First(&existing).Error; err == nil {
		return
	}
	
	// Get subscribers interested in matches and this competition
	subs := na.getSubscribersForType("matches", match.Competition)
	if len(subs) == 0 {
		return
	}
	
	// Build email content
	var subject string
	if notifType == "reminder_48h" {
		subject = fmt.Sprintf("Nadcházející zápas za %d hodin: %s vs %s", hoursBeforeText, match.Home, match.Away)
	} else {
		subject = fmt.Sprintf("Zápas dnes: %s vs %s", match.Home, match.Away)
	}
	
	html := na.buildMatchReminderHTML(match, notifType)
	
	recipients := make([]string, 0, len(subs))
	for _, sub := range subs {
		recipients = append(recipients, sub.Email)
	}
	
	err := na.sendNewsletterToRecipients(recipients, subject, html, "match_reminder")
	if err != nil {
		logger.Error("[newsletter-automation] Failed to send match reminder: %v", err)
		return
	}
	
	// Record notification
	notif := models.MatchNotification{
		MatchID:          matchKey,
		NotificationType: notifType,
		SentAt:           time.Now(),
		RecipientsCount:  len(recipients),
		CreatedAt:        time.Now(),
	}
	na.db.Create(&notif)
	
	log.Printf("[newsletter-automation] Match reminder sent: %s (%s) to %d recipients", matchKey, notifType, len(recipients))
}

func (na *NewsletterAutomation) checkFinishedMatches() {
	var settings models.Settings
	na.db.First(&settings)
	
	if !settings.EnableResults {
		return
	}
	
	// Check quiet hours
	currentHour := time.Now().Hour()
	quietStart := settings.NewsletterQuietStart
	quietEnd := settings.NewsletterQuietEnd
	
	if quietStart > 0 && quietEnd > 0 {
		if quietStart < quietEnd {
			// e.g., 22:00 - 08:00
			if currentHour >= quietStart || currentHour < quietEnd {
				log.Printf("[newsletter-automation] In quiet hours, skipping result notifications")
				return
			}
		} else {
			// e.g., 08:00 - 22:00 (inverted, send only during these hours)
			if currentHour < quietStart && currentHour >= quietEnd {
				log.Printf("[newsletter-automation] Outside active hours, skipping result notifications")
				return
			}
		}
	}
	
	// Load match data
	facr := readJSON(filepath.Join(na.cacheDir, "facr_club_info.json"))
	matches := facrAllMatches(facr)
	
	now := time.Now()
	lookback := 6 * time.Hour // Check matches finished in last 6 hours
	
	for _, match := range matches {
		if match.Score == "" || !strings.Contains(match.Score, ":") {
			continue // No score yet
		}
		
		matchTime := parseDateTimeISO(match.Date, match.Time)
		if matchTime.IsZero() || matchTime.After(now) {
			continue
		}
		
		// Check if match finished recently
		timeSinceMatch := now.Sub(matchTime)
		if timeSinceMatch > lookback {
			continue
		}
		
		na.sendMatchResult(match)
	}
}

func (na *NewsletterAutomation) sendMatchResult(match Match) {
	// Check if already sent
	matchKey := fmt.Sprintf("%s-%s-%s", match.Date, match.Home, match.Away)
	var existing models.MatchNotification
	if err := na.db.Where("match_id = ? AND notification_type = ?", matchKey, "result").First(&existing).Error; err == nil {
		return
	}
	
	// Get subscribers interested in results
	subs := na.getSubscribersForType("scores", match.Competition)
	if len(subs) == 0 {
		return
	}
	
	subject := fmt.Sprintf("Výsledek: %s %s %s", match.Home, match.Score, match.Away)
	html := na.buildMatchResultHTML(match)
	
	recipients := make([]string, 0, len(subs))
	for _, sub := range subs {
		recipients = append(recipients, sub.Email)
	}
	
	err := na.sendNewsletterToRecipients(recipients, subject, html, "match_result")
	if err != nil {
		logger.Error("[newsletter-automation] Failed to send match result: %v", err)
		return
	}
	
	// Record notification
	notif := models.MatchNotification{
		MatchID:          matchKey,
		NotificationType: "result",
		SentAt:           time.Now(),
		RecipientsCount:  len(recipients),
		CreatedAt:        time.Now(),
	}
	na.db.Create(&notif)
	
	log.Printf("[newsletter-automation] Match result sent: %s to %d recipients", matchKey, len(recipients))
}

// Helper functions

func (na *NewsletterAutomation) isEnabled() bool {
	if config.AppConfig == nil {
		return false
	}
	return config.AppConfig.NewsletterEnabled
}

func (na *NewsletterAutomation) getSubscribersForType(contentType, category string) []models.NewsletterSubscription {
	var subs []models.NewsletterSubscription
	na.db.Where("is_active = ?", true).Find(&subs)
	
	filtered := make([]models.NewsletterSubscription, 0)
	for _, sub := range subs {
		// Check if subscriber wants this content type
		if val, ok := sub.Preferences[contentType].(bool); ok && val {
			// If category filtering is needed and specified
			if category != "" {
				// Check if subscriber has category preferences
				if cats, ok := sub.Preferences["categories"].(string); ok && cats != "" {
					categoryList := strings.Split(cats, ",")
					found := false
					for _, cat := range categoryList {
						if strings.EqualFold(strings.TrimSpace(cat), category) {
							found = true
							break
						}
					}
					if !found {
						continue
					}
				}
			}
			filtered = append(filtered, sub)
		}
	}
	
	return filtered
}

func (na *NewsletterAutomation) parsePreferences(sub models.NewsletterSubscription) NewsletterPrefs {
	prefs := NewsletterPrefs{
		Email:        sub.Email,
		ContentTypes: []string{},
		Competitions: []string{},
		Frequency:    "daily",
	}
	
	// Parse content types
	if v, ok := sub.Preferences["blogs"].(bool); ok && v {
		prefs.ContentTypes = append(prefs.ContentTypes, "blogs")
	}
	if v, ok := sub.Preferences["events"].(bool); ok && v {
		prefs.ContentTypes = append(prefs.ContentTypes, "events")
	}
	if v, ok := sub.Preferences["matches"].(bool); ok && v {
		prefs.ContentTypes = append(prefs.ContentTypes, "matches")
	}
	if v, ok := sub.Preferences["scores"].(bool); ok && v {
		prefs.ContentTypes = append(prefs.ContentTypes, "scores")
	}
	
	// Parse categories/competitions
	if cats, ok := sub.Preferences["categories"].(string); ok && cats != "" {
		for _, c := range strings.Split(cats, ",") {
			if v := strings.TrimSpace(c); v != "" {
				prefs.Competitions = append(prefs.Competitions, v)
			}
		}
	}
	
	return prefs
}

func (na *NewsletterAutomation) sendNewsletterToRecipients(recipients []string, subject, htmlContent, newsletterType string) error {
	data := &email.NewsletterData{
		Subject:    subject,
		Content:    htmlContent,
		Recipients: recipients,
	}
	
	err := na.emailSvc.SendNewsletter(data)
	if err != nil {
		return err
	}
	
	// Log sent newsletter
	contentIDsJSON, _ := json.Marshal([]string{})
	logEntry := models.NewsletterSentLog{
		NewsletterType:  newsletterType,
		Subject:         subject,
		ContentIDs:      string(contentIDsJSON),
		RecipientsCount: len(recipients),
		SentAt:          time.Now(),
		CreatedAt:       time.Now(),
	}
	na.db.Create(&logEntry)
	
	return nil
}

// HTML builders

func (na *NewsletterAutomation) buildBlogNotificationHTML(article *models.Article, articleURL string) string {
	baseFE := strings.TrimSuffix(config.AppConfig.FrontendBaseURL, "/")
	
	// Build tracked link
	token, _ := utils.GenerateSubscriberToken("newsletter@system", 60*24*30)
	trackedURL := fmt.Sprintf("%s/api/v1/email/click?u=%s&t=%s", 
		strings.TrimSuffix(config.AppConfig.PublicAPIBaseURL, "/"),
		url.QueryEscape(articleURL),
		url.QueryEscape(token))
	
	html := fmt.Sprintf(`
<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;">%s</h3>
		<p style="color: #4a5568; line-height: 1.6; margin: 0 0 15px 0;">%s</p>
		<a href="%s" 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>
	
	<p style="color: #718096; font-size: 14px; margin-top: 30px;">
		<a href="%s/newsletter/preferences?token=%s" style="color: #2563eb;">Spravovat předvolby</a>
	</p>
</div>
`, htmlEsc(article.Title), htmlEsc(article.Excerpt), trackedURL, baseFE, url.QueryEscape(token))
	
	return html
}

func (na *NewsletterAutomation) buildMatchReminderHTML(match Match, notifType string) string {
	var intro string
	if notifType == "reminder_48h" {
		intro = "Připomínáme nadcházející zápas:"
	} else {
		intro = "Zápas je dnes!"
	}
	
	html := fmt.Sprintf(`
<div style="max-width: 600px; margin: 0 auto; font-family: Arial, sans-serif;">
	<h2 style="color: #1e3a8a; margin-bottom: 20px;">%s</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;">%s vs %s</h3>
		<p style="color: #276749; margin: 5px 0;"><strong>Datum:</strong> %s</p>
		<p style="color: #276749; margin: 5px 0;"><strong>Čas:</strong> %s</p>
		<p style="color: #276749; margin: 5px 0;"><strong>Soutěž:</strong> %s</p>
	</div>
</div>
`, intro, htmlEsc(match.Home), htmlEsc(match.Away), htmlEsc(match.Date), htmlEsc(match.Time), htmlEsc(match.Competition))
	
	return html
}

func (na *NewsletterAutomation) buildMatchResultHTML(match Match) string {
	html := fmt.Sprintf(`
<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;">%s <span style="color: #d69e2e;">%s</span> %s</h3>
		<p style="color: #975a16; margin: 5px 0;"><strong>Datum:</strong> %s</p>
		<p style="color: #975a16; margin: 5px 0;"><strong>Soutěž:</strong> %s</p>
	</div>
</div>
`, htmlEsc(match.Home), htmlEsc(match.Score), htmlEsc(match.Away), htmlEsc(match.Date), htmlEsc(match.Competition))
	
	return html
}
