package handlers

import (
	"fmt"
	"net/http"
	"strconv"
	"time"
	"whereismymoney/internal/models"
	"whereismymoney/internal/views"

	"github.com/gin-gonic/gin"
	"github.com/gorilla/sessions"
	"golang.org/x/crypto/bcrypt"
	"gorm.io/gorm"
)

type Handler struct {
	DB    *gorm.DB
	Store *sessions.CookieStore
}

func NewHandler(db *gorm.DB) *Handler {
	store := sessions.NewCookieStore([]byte("your-secret-key-here"))
	
	// Session-Optionen für Safari-Kompatibilität
	store.Options = &sessions.Options{
		Path:     "/",
		MaxAge:   86400 * 7, // 7 Tage
		HttpOnly: true,
		Secure:   false, // Für localhost Development
		SameSite: http.SameSiteLaxMode, // Safari-kompatibel
	}
	
	return &Handler{
		DB:    db,
		Store: store,
	}
}

// Dashboard zeigt das Hauptdashboard (nur für angemeldete Benutzer)
func (h *Handler) Dashboard(c *gin.Context) {
	// Session überprüfen
	session, _ := h.Store.Get(c.Request, "user-session")
	userID, ok := session.Values["user_id"]
	if !ok {
		c.Redirect(http.StatusSeeOther, "/login?error=required")
		return
	}

	// Benutzer aus der Datenbank laden
	var user models.User
	if err := h.DB.First(&user, userID).Error; err != nil {
		c.Redirect(http.StatusSeeOther, "/login?error=required")
		return
	}

	// Testdaten generieren falls nötig
	h.generateTestData(userID.(uint))

	// Wiederkehrende Transaktionen generieren
	h.processRecurringTransactions(userID.(uint))

	// Dashboard-Daten sammeln
	dashboardData, err := h.generateDashboardData(userID.(uint))
	if err != nil {
		c.String(http.StatusInternalServerError, "Fehler beim Laden der Dashboard-Daten: %v", err)
		return
	}

	// Dashboard rendern
	component := views.Dashboard(dashboardData)
	component.Render(c.Request.Context(), c.Writer)
}

// DashboardDataAPI liefert Dashboard-Daten als JSON für AJAX-Anfragen
func (h *Handler) DashboardDataAPI(c *gin.Context) {
	// Session überprüfen
	session, _ := h.Store.Get(c.Request, "user-session")
	userID, ok := session.Values["user_id"]
	if !ok {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "Nicht angemeldet"})
		return
	}

	// Testdaten generieren falls nötig
	h.generateTestData(userID.(uint))

	// Wiederkehrende Transaktionen generieren
	h.processRecurringTransactions(userID.(uint))

	// Dashboard-Daten generieren
	data, err := h.generateDashboardData(userID.(uint))
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Fehler beim Laden der Dashboard-Daten"})
		return
	}

	// Daten als JSON zurückgeben
	c.JSON(http.StatusOK, data)
}

// generateDashboardData sammelt alle Daten für das Dashboard
func (h *Handler) generateDashboardData(userID uint) (*models.DashboardData, error) {
	data := &models.DashboardData{}
	
	// Wiederkehrende Transaktionen verarbeiten BEVOR Dashboard-Daten generiert werden
	if err := h.processRecurringTransactions(userID); err != nil {
		// Fehler loggen, aber nicht den gesamten Dashboard-Aufruf fehlschlagen lassen
		fmt.Printf("Fehler beim Verarbeiten wiederkehrender Transaktionen: %v\n", err)
	}
	
	// Benutzer laden
	var user models.User
	if err := h.DB.First(&user, userID).Error; err != nil {
		return nil, err
	}
	data.UserName = user.Name

	// Vermögensübersicht generieren
	assetOverview, err := h.generateAssetOverview(userID)
	if err != nil {
		return nil, err
	}
	data.AssetOverview = *assetOverview

	// Monatliche Statistiken generieren
	monthlyStats, err := h.generateMonthlyStats(userID)
	if err != nil {
		return nil, err
	}
	data.MonthlyStats = monthlyStats

	// Kategorie-Statistiken generieren
	categoryStats, err := h.generateCategoryStats(userID)
	if err != nil {
		return nil, err
	}
	data.CategoryStats = categoryStats

	// Transaktionstrends generieren
	transactionTrend, err := h.generateTransactionTrend(userID)
	if err != nil {
		return nil, err
	}
	data.TransactionTrend = transactionTrend

	// Aktuelle Transaktionen laden
	recentTransactions, err := h.getRecentTransactions(userID)
	if err != nil {
		return nil, err
	}
	data.RecentTransactions = recentTransactions

	// Wöchentliche Statistiken generieren
	weeklyStats, err := h.generateWeeklyStats(userID)
	if err != nil {
		return nil, err
	}
	data.WeeklyStats = weeklyStats

	return data, nil
}

// generateAssetOverview erstellt eine Vermögensübersicht
func (h *Handler) generateAssetOverview(userID uint) (*models.AssetOverview, error) {
	overview := &models.AssetOverview{}

	// Bank-Konten laden
	var bankAccounts []models.BankAccount
	if err := h.DB.Where("user_id = ?", userID).Find(&bankAccounts).Error; err != nil {
		return nil, err
	}

	totalBankBalance := 0.0
	bankSummaries := make([]models.BankAccountSummary, len(bankAccounts))
	for i, account := range bankAccounts {
		totalBankBalance += account.Balance
		bankSummaries[i] = models.BankAccountSummary{
			ID:          account.ID,
			Name:        account.Name,
			Bank:        account.Bank,
			AccountType: account.AccountType,
			Balance:     account.Balance,
		}
	}

	// Depots laden
	var depots []models.Depot
	if err := h.DB.Where("user_id = ?", userID).Find(&depots).Error; err != nil {
		return nil, err
	}

	totalDepotValue := 0.0
	depotSummaries := make([]models.DepotSummary, len(depots))
	for i, depot := range depots {
		totalDepotValue += depot.TotalValue
		depotSummaries[i] = models.DepotSummary{
			ID:         depot.ID,
			Name:       depot.Name,
			Broker:     depot.Broker,
			TotalValue: depot.TotalValue,
		}
	}

	overview.TotalBankBalance = totalBankBalance
	overview.TotalDepotValue = totalDepotValue
	overview.TotalAssets = totalBankBalance + totalDepotValue
	overview.BankAccounts = bankSummaries
	overview.Depots = depotSummaries

	return overview, nil
}

// generateMonthlyStats erstellt monatliche Statistiken
func (h *Handler) generateMonthlyStats(userID uint) ([]models.MonthlyStats, error) {
	var stats []models.MonthlyStats
	
	// Letzte 12 Monate
	now := time.Now()
	for i := 11; i >= 0; i-- {
		month := now.AddDate(0, -i, 0)
		startOfMonth := time.Date(month.Year(), month.Month(), 1, 0, 0, 0, 0, month.Location())
		endOfMonth := startOfMonth.AddDate(0, 1, 0).Add(-time.Nanosecond)
		
		var income, expenses float64
		
		// Einnahmen berechnen
		h.DB.Model(&models.Transaction{}).
			Where("user_id = ? AND type = ? AND date >= ? AND date <= ?", userID, "income", startOfMonth, endOfMonth).
			Select("COALESCE(SUM(amount), 0)").Scan(&income)
			
		// Ausgaben berechnen
		h.DB.Model(&models.Transaction{}).
			Where("user_id = ? AND type = ? AND date >= ? AND date <= ?", userID, "expense", startOfMonth, endOfMonth).
			Select("COALESCE(SUM(amount), 0)").Scan(&expenses)
		
		netChange := income - expenses
		
		// Balance zu diesem Zeitpunkt (vereinfacht)
		var balance float64
		h.DB.Model(&models.Transaction{}).
			Where("user_id = ? AND date <= ?", userID, endOfMonth).
			Select("COALESCE(SUM(CASE WHEN type = 'income' THEN amount ELSE -amount END), 0)").Scan(&balance)
		
		stats = append(stats, models.MonthlyStats{
			Month:     month.Format("2006-01"),
			Income:    income,
			Expenses:  expenses,
			NetChange: netChange,
			Balance:   balance,
		})
	}
	
	return stats, nil
}

// generateCategoryStats erstellt Kategorie-Statistiken
func (h *Handler) generateCategoryStats(userID uint) ([]models.CategoryStats, error) {
	var stats []models.CategoryStats
	
	// Letzte 90 Tage für bessere Relevanz
	ninetyDaysAgo := time.Now().AddDate(0, 0, -90)
	
	type categoryResult struct {
		CategoryID   *uint
		CategoryName *string
		TotalAmount  float64
		Count        int64
	}
	
	var results []categoryResult
	
	query := `
		SELECT 
			t.category_id,
			c.name as category_name,
			SUM(t.amount) as total_amount,
			COUNT(*) as count
		FROM transactions t
		LEFT JOIN categories c ON t.category_id = c.id
		WHERE t.user_id = ? AND t.date >= ? AND t.type = 'expense'
		GROUP BY t.category_id, c.name
		ORDER BY total_amount DESC
	`
	
	if err := h.DB.Raw(query, userID, ninetyDaysAgo).Scan(&results).Error; err != nil {
		return nil, err
	}
	
	// Gesamtsumme für Prozentberechnung
	var totalExpenses float64
	for _, result := range results {
		totalExpenses += result.TotalAmount
	}
	
	for _, result := range results {
		categoryName := "Ohne Kategorie"
		var categoryID uint = 0
		
		if result.CategoryID != nil {
			categoryID = *result.CategoryID
		}
		if result.CategoryName != nil {
			categoryName = *result.CategoryName
		}
		
		percentage := 0.0
		if totalExpenses > 0 {
			percentage = (result.TotalAmount / totalExpenses) * 100
		}
		
		stats = append(stats, models.CategoryStats{
			CategoryID:   categoryID,
			CategoryName: categoryName,
			TotalAmount:  result.TotalAmount,
			Count:        int(result.Count),
			Percentage:   percentage,
		})
	}
	
	return stats, nil
}

// generateTransactionTrend erstellt Verlaufsdaten für Charts
func (h *Handler) generateTransactionTrend(userID uint) ([]models.TransactionTrend, error) {
	var trends []models.TransactionTrend
	
	// Nächste 12 Monate (für Trend mit wiederkehrenden Transaktionen)
	now := time.Now()
	
	// 12 Monate gruppiert nach Monaten
	for i := 0; i < 12; i++ {
		// Erster Tag des Monats
		monthStart := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location()).AddDate(0, i, 0)
		// Letzter Tag des Monats
		monthEnd := monthStart.AddDate(0, 1, 0).Add(-time.Nanosecond)
		
		var income, expense float64
		
		// Einnahmen für diesen Monat (mit DATE-Funktion)
		h.DB.Model(&models.Transaction{}).
			Where("user_id = ? AND type = ? AND date >= ? AND date < ?", userID, "income", monthStart, monthEnd.AddDate(0, 0, 1)).
			Select("COALESCE(SUM(amount), 0)").Scan(&income)
			
		// Ausgaben für diesen Monat (mit DATE-Funktion)
		h.DB.Model(&models.Transaction{}).
			Where("user_id = ? AND type = ? AND date >= ? AND date < ?", userID, "expense", monthStart, monthEnd.AddDate(0, 0, 1)).
			Select("COALESCE(SUM(amount), 0)").Scan(&expense)
		
		// Aktueller Kontostand berechnen
		var balance float64
		if i == 0 {
			// Für den ersten Monat: Aktueller Stand aus allen vergangenen Transaktionen
			h.DB.Model(&models.Transaction{}).
				Where("user_id = ? AND date <= ?", userID, monthEnd).
				Select("COALESCE(SUM(CASE WHEN type = 'income' THEN amount ELSE -amount END), 0)").Scan(&balance)
		} else {
			// Für zukünftige Monate: Vorheriger Balance + heutige Einnahmen - heutige Ausgaben
			if len(trends) > 0 {
				balance = trends[len(trends)-1].Balance + income - expense
			}
		}
		
		trends = append(trends, models.TransactionTrend{
			Date:    monthStart,
			Income:  income,
			Expense: expense,
			Balance: balance,
		})
	}
	
	return trends, nil
}

// getRecentTransactions lädt die neuesten Transaktionen
func (h *Handler) getRecentTransactions(userID uint) ([]models.Transaction, error) {
	var transactions []models.Transaction
	
	err := h.DB.Where("user_id = ?", userID).
		Preload("Category").
		Preload("BankAccount").
		Order("date DESC, created_at DESC").
		Limit(10).
		Find(&transactions).Error
	
	return transactions, err
}

// generateWeeklyStats erstellt wöchentliche Statistiken
func (h *Handler) generateWeeklyStats(userID uint) ([]models.WeeklyStats, error) {
	var stats []models.WeeklyStats
	
	// Letzte 4 Wochen
	now := time.Now()
	for i := 3; i >= 0; i-- {
		// Wochenstart (Montag)
		weekStart := now.AddDate(0, 0, -7*i)
		for weekStart.Weekday() != time.Monday {
			weekStart = weekStart.AddDate(0, 0, -1)
		}
		weekStart = time.Date(weekStart.Year(), weekStart.Month(), weekStart.Day(), 0, 0, 0, 0, weekStart.Location())
		weekEnd := weekStart.AddDate(0, 0, 6).Add(23*time.Hour + 59*time.Minute + 59*time.Second)
		
		var income, expenses float64
		
		// Einnahmen berechnen
		h.DB.Model(&models.Transaction{}).
			Where("user_id = ? AND type = ? AND date >= ? AND date <= ?", userID, "income", weekStart, weekEnd).
			Select("COALESCE(SUM(amount), 0)").Scan(&income)
			
		// Ausgaben berechnen
		h.DB.Model(&models.Transaction{}).
			Where("user_id = ? AND type = ? AND date >= ? AND date <= ?", userID, "expense", weekStart, weekEnd).
			Select("COALESCE(SUM(amount), 0)").Scan(&expenses)
		
		netChange := income - expenses
		weekLabel := fmt.Sprintf("KW %d", getWeekNumber(weekStart))
		
		stats = append(stats, models.WeeklyStats{
			Week:      weekLabel,
			Income:    income,
			Expenses:  expenses,
			NetChange: netChange,
			StartDate: weekStart,
			EndDate:   weekEnd,
		})
	}
	
	return stats, nil
}

// getWeekNumber berechnet die Kalenderwoche
func getWeekNumber(date time.Time) int {
	_, week := date.ISOWeek()
	return week
}

// ShowLogin zeigt die Login-Seite
func (h *Handler) ShowLogin(c *gin.Context) {
	errorMsg := ""
	switch c.Query("error") {
	case "invalid":
		errorMsg = "Ungültige E-Mail-Adresse oder Passwort"
	case "session":
		errorMsg = "Fehler beim Erstellen der Sitzung. Bitte versuchen Sie es erneut."
	case "required":
		errorMsg = "Bitte melden Sie sich an, um diese Seite zu besuchen"
	}
	
	component := views.LoginPage(errorMsg)
	component.Render(c.Request.Context(), c.Writer)
}

// ShowRegister zeigt die Registrierungs-Seite
func (h *Handler) ShowRegister(c *gin.Context) {
	errorMsg := ""
	switch c.Query("error") {
	case "password_mismatch":
		errorMsg = "Die Passwörter stimmen nicht überein"
	case "email_exists":
		errorMsg = "Ein Konto mit dieser E-Mail-Adresse existiert bereits"
	case "server":
		errorMsg = "Ein Server-Fehler ist aufgetreten. Bitte versuchen Sie es erneut."
	case "session":
		errorMsg = "Fehler beim Erstellen der Sitzung. Bitte versuchen Sie es erneut."
	}
	
	component := views.RegisterPage(errorMsg)
	component.Render(c.Request.Context(), c.Writer)
}

// Login verarbeitet die Anmeldung
func (h *Handler) Login(c *gin.Context) {
	email := c.PostForm("email")
	password := c.PostForm("password")

	// Benutzer in der Datenbank finden
	var user models.User
	if err := h.DB.Where("email = ?", email).First(&user).Error; err != nil {
		c.Redirect(http.StatusSeeOther, "/login?error=invalid")
		return
	}

	// Passwort überprüfen
	if !user.CheckPassword(password) {
		c.Redirect(http.StatusSeeOther, "/login?error=invalid")
		return
	}

	// Session erstellen
	session, _ := h.Store.Get(c.Request, "user-session")
	session.Values["user_id"] = user.ID
	session.Values["user_name"] = user.Name
	
	// Session explizit speichern mit Fehlerbehandlung
	if err := session.Save(c.Request, c.Writer); err != nil {
		c.Redirect(http.StatusSeeOther, "/login?error=session")
		return
	}

	c.Redirect(http.StatusSeeOther, "/")
}

// Register verarbeitet die Registrierung
func (h *Handler) Register(c *gin.Context) {
	name := c.PostForm("name")
	email := c.PostForm("email")
	password := c.PostForm("password")
	passwordConfirm := c.PostForm("password_confirm")

	// Passwort-Bestätigung überprüfen
	if password != passwordConfirm {
		c.Redirect(http.StatusSeeOther, "/register?error=password_mismatch")
		return
	}

	// Neuen Benutzer erstellen
	user := models.User{
		Name:  name,
		Email: email,
	}

	// Passwort hashen
	if err := user.HashPassword(password); err != nil {
		c.Redirect(http.StatusSeeOther, "/register?error=server")
		return
	}

	// Benutzer in der Datenbank speichern
	if err := h.DB.Create(&user).Error; err != nil {
		c.Redirect(http.StatusSeeOther, "/register?error=email_exists")
		return
	}

	// Session erstellen
	session, _ := h.Store.Get(c.Request, "user-session")
	session.Values["user_id"] = user.ID
	session.Values["user_name"] = user.Name
	
	// Session explizit speichern mit Fehlerbehandlung
	if err := session.Save(c.Request, c.Writer); err != nil {
		c.Redirect(http.StatusSeeOther, "/register?error=session")
		return
	}

	c.Redirect(http.StatusSeeOther, "/")
}

// Logout meldet den Benutzer ab
func (h *Handler) Logout(c *gin.Context) {
	session, _ := h.Store.Get(c.Request, "user-session")
	session.Values["user_id"] = nil
	session.Values["user_name"] = nil
	session.Options.MaxAge = -1
	session.Save(c.Request, c.Writer)

	c.Redirect(http.StatusSeeOther, "/login")
}

// ShowAccounts zeigt die Konten- und Depot-Verwaltung
func (h *Handler) ShowAccounts(c *gin.Context) {
	// Session überprüfen
	session, _ := h.Store.Get(c.Request, "user-session")
	userID, ok := session.Values["user_id"]
	if !ok {
		c.Redirect(http.StatusSeeOther, "/login?error=required")
		return
	}

	userName, _ := session.Values["user_name"].(string)

	// Bankkonten laden
	var bankAccounts []models.BankAccount
	h.DB.Where("user_id = ?", userID).Find(&bankAccounts)

	// Depots laden
	var depots []models.Depot
	h.DB.Where("user_id = ?", userID).Find(&depots)

	// Template rendern
	views.Accounts(userName, bankAccounts, depots).Render(c.Request.Context(), c.Writer)
}

// CreateBankAccount erstellt ein neues Bankkonto
func (h *Handler) CreateBankAccount(c *gin.Context) {
	// Session überprüfen
	session, _ := h.Store.Get(c.Request, "user-session")
	userID, ok := session.Values["user_id"]
	if !ok {
		c.Redirect(http.StatusSeeOther, "/login?error=required")
		return
	}

	// Formulardaten lesen
	name := c.PostForm("name")
	bankName := c.PostForm("bank_name")
	accountType := c.PostForm("account_type")
	iban := c.PostForm("iban")
	
	// Balance parsen
	var balance float64
	if balanceStr := c.PostForm("balance"); balanceStr != "" {
		if parsed, err := parseFloat(balanceStr); err == nil {
			balance = parsed
		}
	}

	// Validierung
	if name == "" || bankName == "" || accountType == "" {
		c.Redirect(http.StatusSeeOther, "/accounts?error=required_fields")
		return
	}

	// Bankkonto erstellen
	bankAccount := models.BankAccount{
		UserID:      userID.(uint),
		Name:        name,
		Bank:        bankName,
		AccountType: accountType,
		IBAN:        iban,
		Balance:     balance,
	}

	if err := h.DB.Create(&bankAccount).Error; err != nil {
		c.Redirect(http.StatusSeeOther, "/accounts?error=create_failed")
		return
	}

	c.Redirect(http.StatusSeeOther, "/accounts?success=bank_created")
}

// CreateDepot erstellt ein neues Depot
func (h *Handler) CreateDepot(c *gin.Context) {
	// Session überprüfen
	session, _ := h.Store.Get(c.Request, "user-session")
	userID, ok := session.Values["user_id"]
	if !ok {
		c.Redirect(http.StatusSeeOther, "/login?error=required")
		return
	}

	// Formulardaten lesen
	name := c.PostForm("name")
	brokerName := c.PostForm("broker_name")
	depotNumber := c.PostForm("depot_number")
	
	// Total Value parsen
	var totalValue float64
	if valueStr := c.PostForm("total_value"); valueStr != "" {
		if parsed, err := parseFloat(valueStr); err == nil {
			totalValue = parsed
		}
	}

	// Validierung
	if name == "" || brokerName == "" {
		c.Redirect(http.StatusSeeOther, "/accounts?error=required_fields")
		return
	}

	// Depot erstellen
	depot := models.Depot{
		UserID:       userID.(uint),
		Name:         name,
		Broker:       brokerName,
		DepotNumber:  depotNumber,
		TotalValue:   totalValue,
	}

	if err := h.DB.Create(&depot).Error; err != nil {
		c.Redirect(http.StatusSeeOther, "/accounts?error=create_failed")
		return
	}

	c.Redirect(http.StatusSeeOther, "/accounts?success=depot_created")
}

// parseFloat ist eine Hilfsfunktion zum sicheren Parsen von Float-Werten
func parseFloat(s string) (float64, error) {
	if s == "" {
		return 0, nil
	}
	return strconv.ParseFloat(s, 64)
}

// ShowTransactions zeigt die Transaktionsübersicht
func (h *Handler) ShowTransactions(c *gin.Context) {
	// Session überprüfen
	session, _ := h.Store.Get(c.Request, "user-session")
	userID, ok := session.Values["user_id"]
	if !ok {
		c.Redirect(http.StatusSeeOther, "/login?error=required")
		return
	}

	userName, _ := session.Values["user_name"].(string)

	// Paginierung Parameter
	page := 1
	if pageStr := c.Query("page"); pageStr != "" {
		if p, err := strconv.Atoi(pageStr); err == nil && p > 0 {
			page = p
		}
	}
	
	pageSize := 20
	offset := (page - 1) * pageSize

	// Filter Parameter
	dateFrom := c.Query("date_from")
	dateTo := c.Query("date_to")
	searchDescription := c.Query("search_description")
	filterCategory := c.Query("filter_category")
	filterAccount := c.Query("filter_account")
	filterType := c.Query("filter_type")
	amountMin := c.Query("amount_min")
	amountMax := c.Query("amount_max")

	// Base Query für Transaktionen
	query := h.DB.Model(&models.Transaction{}).Where("user_id = ?", userID)

	// Filter anwenden
	if dateFrom != "" {
		if parsedDate, err := time.Parse("2006-01-02", dateFrom); err == nil {
			query = query.Where("date >= ?", parsedDate)
		}
	}
	if dateTo != "" {
		if parsedDate, err := time.Parse("2006-01-02", dateTo); err == nil {
			query = query.Where("date <= ?", parsedDate)
		}
	}
	if searchDescription != "" {
		query = query.Where("description LIKE ?", "%"+searchDescription+"%")
	}
	if filterCategory != "" {
		if filterCategory == "none" {
			query = query.Where("category_id IS NULL")
		} else if categoryID, err := strconv.Atoi(filterCategory); err == nil {
			query = query.Where("category_id = ?", categoryID)
		}
	}
	if filterAccount != "" {
		if accountID, err := strconv.Atoi(filterAccount); err == nil {
			query = query.Where("bank_account_id = ?", accountID)
		}
	}
	if filterType != "" {
		query = query.Where("type = ?", filterType)
	}
	if amountMin != "" {
		if minAmount, err := strconv.ParseFloat(amountMin, 64); err == nil {
			query = query.Where("amount >= ?", minAmount)
		}
	}
	if amountMax != "" {
		if maxAmount, err := strconv.ParseFloat(amountMax, 64); err == nil {
			query = query.Where("amount <= ?", maxAmount)
		}
	}

	// Gesamtanzahl der gefilterten Transaktionen für Paginierung
	var totalCount int64
	query.Count(&totalCount)
	
	totalPages := int((totalCount + int64(pageSize) - 1) / int64(pageSize))

	// Transaktionen laden (neueste zuerst, mit Paginierung und Filtern)
	var transactions []models.Transaction
	query.Preload("Category").
		Preload("BankAccount").
		Preload("RecurrenceRule").
		Order("date DESC").
		Limit(pageSize).
		Offset(offset).
		Find(&transactions)

	// Bankkonten für Dropdown laden
	var bankAccounts []models.BankAccount
	h.DB.Where("user_id = ?", userID).Find(&bankAccounts)

	// Kategorien laden
	var categories []models.Category
	h.DB.Where("user_id = ?", userID).Find(&categories)

	// Regelmäßige Transaktionen laden
	var recurrenceRules []models.RecurrenceRule
	h.DB.Where("user_id = ? AND is_active = ?", userID, true).
		Preload("Category").
		Preload("BankAccount").
		Find(&recurrenceRules)

	// Template rendern
	views.Transactions(userName, transactions, bankAccounts, categories, recurrenceRules, page, totalPages, totalCount).Render(c.Request.Context(), c.Writer)
}

// CreateTransaction erstellt eine neue Transaktion
func (h *Handler) CreateTransaction(c *gin.Context) {
	// Session überprüfen
	session, _ := h.Store.Get(c.Request, "user-session")
	userID, ok := session.Values["user_id"]
	if !ok {
		c.Redirect(http.StatusSeeOther, "/login?error=required")
		return
	}

	// Formulardaten lesen
	description := c.PostForm("description")
	amountStr := c.PostForm("amount")
	transactionType := c.PostForm("type") // "income" or "expense"
	dateStr := c.PostForm("date")
	categoryIDStr := c.PostForm("category_id")
	bankAccountIDStr := c.PostForm("bank_account_id")

	// Validierung
	if description == "" || amountStr == "" || transactionType == "" || dateStr == "" {
		c.Redirect(http.StatusSeeOther, "/transactions?error=required_fields")
		return
	}

	// Amount parsen
	amount, err := strconv.ParseFloat(amountStr, 64)
	if err != nil {
		c.Redirect(http.StatusSeeOther, "/transactions?error=invalid_amount")
		return
	}

	// Datum parsen
	date, err := time.Parse("2006-01-02", dateStr)
	if err != nil {
		c.Redirect(http.StatusSeeOther, "/transactions?error=invalid_date")
		return
	}

	// Optional: Category ID parsen
	var categoryID *uint
	if categoryIDStr != "" && categoryIDStr != "0" {
		if parsed, err := strconv.ParseUint(categoryIDStr, 10, 32); err == nil {
			id := uint(parsed)
			categoryID = &id
		}
	}

	// Optional: Bank Account ID parsen
	var bankAccountID *uint
	if bankAccountIDStr != "" && bankAccountIDStr != "0" {
		if parsed, err := strconv.ParseUint(bankAccountIDStr, 10, 32); err == nil {
			id := uint(parsed)
			bankAccountID = &id
		}
	}

	// Transaktion erstellen
	transaction := models.Transaction{
		UserID:        userID.(uint),
		Amount:        amount,
		Description:   description,
		Type:          transactionType,
		Date:          date,
		CategoryID:    categoryID,
		BankAccountID: bankAccountID,
		IsRecurring:   false,
	}

	if err := h.DB.Create(&transaction).Error; err != nil {
		c.Redirect(http.StatusSeeOther, "/transactions?error=create_failed")
		return
	}

	c.Redirect(http.StatusSeeOther, "/transactions?success=transaction_created")
}

// CreateRecurringTransaction erstellt eine neue regelmäßige Transaktion
func (h *Handler) CreateRecurringTransaction(c *gin.Context) {
	// Session überprüfen
	session, _ := h.Store.Get(c.Request, "user-session")
	userID, ok := session.Values["user_id"]
	if !ok {
		c.Redirect(http.StatusSeeOther, "/login?error=required")
		return
	}

	// Formulardaten lesen
	description := c.PostForm("description")
	amountStr := c.PostForm("amount")
	transactionType := c.PostForm("type")
	startDateStr := c.PostForm("start_date")
	endDateStr := c.PostForm("end_date")
	interval := c.PostForm("interval")
	intervalCountStr := c.PostForm("interval_count")
	categoryIDStr := c.PostForm("category_id")
	bankAccountIDStr := c.PostForm("bank_account_id")
	dayOfMonthStr := c.PostForm("day_of_month")
	dayOfWeekStr := c.PostForm("day_of_week")

	// Validierung
	if description == "" || amountStr == "" || transactionType == "" || startDateStr == "" || interval == "" {
		c.Redirect(http.StatusSeeOther, "/transactions?error=required_fields")
		return
	}

	// Amount parsen
	amount, err := strconv.ParseFloat(amountStr, 64)
	if err != nil {
		c.Redirect(http.StatusSeeOther, "/transactions?error=invalid_amount")
		return
	}

	// Start-Datum parsen
	startDate, err := time.Parse("2006-01-02", startDateStr)
	if err != nil {
		c.Redirect(http.StatusSeeOther, "/transactions?error=invalid_date")
		return
	}

	// End-Datum parsen (optional)
	var endDate *time.Time
	if endDateStr != "" {
		if parsed, err := time.Parse("2006-01-02", endDateStr); err == nil {
			endDate = &parsed
		}
	}

	// Interval Count parsen
	intervalCount := 1
	if intervalCountStr != "" {
		if parsed, err := strconv.Atoi(intervalCountStr); err == nil && parsed > 0 {
			intervalCount = parsed
		}
	}

	// Optional: Category ID parsen
	var categoryID *uint
	if categoryIDStr != "" && categoryIDStr != "0" {
		if parsed, err := strconv.ParseUint(categoryIDStr, 10, 32); err == nil {
			id := uint(parsed)
			categoryID = &id
		}
	}

	// Optional: Bank Account ID parsen
	var bankAccountID *uint
	if bankAccountIDStr != "" && bankAccountIDStr != "0" {
		if parsed, err := strconv.ParseUint(bankAccountIDStr, 10, 32); err == nil {
			id := uint(parsed)
			bankAccountID = &id
		}
	}

	// Optional: Day of Month parsen
	var dayOfMonth *int
	if dayOfMonthStr != "" {
		if parsed, err := strconv.Atoi(dayOfMonthStr); err == nil && parsed >= 1 && parsed <= 31 {
			dayOfMonth = &parsed
		}
	}

	// Optional: Day of Week parsen
	var dayOfWeek *int
	if dayOfWeekStr != "" {
		if parsed, err := strconv.Atoi(dayOfWeekStr); err == nil && parsed >= 0 && parsed <= 6 {
			dayOfWeek = &parsed
		}
	}

	// RecurrenceRule erstellen
	recurrenceRule := models.RecurrenceRule{
		UserID:        userID.(uint),
		Amount:        amount,
		Description:   description,
		Type:          transactionType,
		CategoryID:    categoryID,
		BankAccountID: bankAccountID,
		Interval:      interval,
		IntervalCount: intervalCount,
		StartDate:     startDate,
		EndDate:       endDate,
		DayOfMonth:    dayOfMonth,
		DayOfWeek:     dayOfWeek,
		IsActive:      true,
	}

	if err := h.DB.Create(&recurrenceRule).Error; err != nil {
		c.Redirect(http.StatusSeeOther, "/transactions?error=create_failed")
		return
	}

	c.Redirect(http.StatusSeeOther, "/transactions?success=recurring_created")
}

// DeleteTransaction löscht eine Transaktion
func (h *Handler) DeleteTransaction(c *gin.Context) {
	// Session überprüfen
	session, _ := h.Store.Get(c.Request, "user-session")
	userID, ok := session.Values["user_id"]
	if !ok {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "Nicht angemeldet"})
		return
	}

	// Transaction ID aus URL Parameter
	transactionIDStr := c.Param("id")
	transactionID, err := strconv.ParseUint(transactionIDStr, 10, 32)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Ungültige Transaktions-ID"})
		return
	}

	// Transaktion löschen (nur wenn sie dem Benutzer gehört)
	result := h.DB.Where("id = ? AND user_id = ?", transactionID, userID).Delete(&models.Transaction{})
	if result.Error != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Fehler beim Löschen"})
		return
	}

	if result.RowsAffected == 0 {
		c.JSON(http.StatusNotFound, gin.H{"error": "Transaktion nicht gefunden"})
		return
	}

	c.JSON(http.StatusOK, gin.H{"success": true})
}

// GetTransactionData gibt die Daten einer Transaktion für das Edit-Modal zurück
func (h *Handler) GetTransactionData(c *gin.Context) {
	// Session überprüfen
	session, _ := h.Store.Get(c.Request, "user-session")
	userID, ok := session.Values["user_id"]
	if !ok {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "Nicht angemeldet"})
		return
	}

	// Transaction ID aus URL Parameter
	transactionIDStr := c.Param("id")
	transactionID, err := strconv.ParseUint(transactionIDStr, 10, 32)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Ungültige Transaktions-ID"})
		return
	}

	// Transaktion laden
	var transaction models.Transaction
	result := h.DB.Where("id = ? AND user_id = ?", transactionID, userID).First(&transaction)
	if result.Error != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "Transaktion nicht gefunden"})
		return
	}

	// Daten für JavaScript formatieren
	transactionData := gin.H{
		"id":              transaction.ID,
		"description":     transaction.Description,
		"amount":          transaction.Amount,
		"type":            transaction.Type,
		"date":            transaction.Date.Format("2006-01-02"),
		"category_id":     transaction.CategoryID,
		"bank_account_id": transaction.BankAccountID,
	}

	c.JSON(http.StatusOK, transactionData)
}

// UpdateTransaction aktualisiert eine existierende Transaktion
func (h *Handler) UpdateTransaction(c *gin.Context) {
	// Session überprüfen
	session, _ := h.Store.Get(c.Request, "user-session")
	userID, ok := session.Values["user_id"]
	if !ok {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "Nicht angemeldet"})
		return
	}

	// Transaction ID aus URL Parameter
	transactionIDStr := c.Param("id")
	transactionID, err := strconv.ParseUint(transactionIDStr, 10, 32)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Ungültige Transaktions-ID"})
		return
	}

	// JSON Body parsen
	var reqData struct {
		Description     string `json:"description"`
		Amount          string `json:"amount"`
		Type            string `json:"type"`
		Date            string `json:"date"`
		CategoryID      string `json:"category_id"`
		BankAccountID   string `json:"bank_account_id"`
	}

	if err := c.ShouldBindJSON(&reqData); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Ungültige Daten"})
		return
	}

	// Daten validieren und konvertieren
	amount, err := strconv.ParseFloat(reqData.Amount, 64)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Ungültiger Betrag"})
		return
	}

	date, err := time.Parse("2006-01-02", reqData.Date)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Ungültiges Datum"})
		return
	}

	bankAccountID, err := strconv.ParseUint(reqData.BankAccountID, 10, 32)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Ungültige Konto-ID"})
		return
	}

	// Optional: Category ID parsen
	var categoryID *uint
	if reqData.CategoryID != "" && reqData.CategoryID != "0" {
		if parsed, err := strconv.ParseUint(reqData.CategoryID, 10, 32); err == nil {
			id := uint(parsed)
			categoryID = &id
		}
	}

	// Transaktion laden und aktualisieren
	var transaction models.Transaction
	result := h.DB.Where("id = ? AND user_id = ?", transactionID, userID).First(&transaction)
	if result.Error != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "Transaktion nicht gefunden"})
		return
	}

	// Transaktion aktualisieren
	transaction.Description = reqData.Description
	transaction.Amount = amount
	transaction.Type = reqData.Type
	transaction.Date = date
	transaction.CategoryID = categoryID
	bankID := uint(bankAccountID)
	transaction.BankAccountID = &bankID

	if err := h.DB.Save(&transaction).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Fehler beim Speichern"})
		return
	}

	c.JSON(http.StatusOK, gin.H{"success": true})
}

// MultiUpdateTransactions aktualisiert mehrere Transaktionen gleichzeitig
func (h *Handler) MultiUpdateTransactions(c *gin.Context) {
	// Session überprüfen
	session, _ := h.Store.Get(c.Request, "user-session")
	userID, ok := session.Values["user_id"]
	if !ok {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "Nicht angemeldet"})
		return
	}

	// JSON Request parsen
	var reqData struct {
		TransactionIDs []string `json:"transaction_ids"`
		Description    *string  `json:"description,omitempty"`
		Amount         *string  `json:"amount,omitempty"`
		Type           *string  `json:"type,omitempty"`
		Date           *string  `json:"date,omitempty"`
		CategoryID     *string  `json:"category_id,omitempty"`
		BankAccountID  *string  `json:"bank_account_id,omitempty"`
	}

	if err := c.ShouldBindJSON(&reqData); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Ungültige Anfrage"})
		return
	}

	if len(reqData.TransactionIDs) == 0 {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Keine Transaktionen ausgewählt"})
		return
	}

	// Updates vorbereiten
	updates := make(map[string]interface{})

	if reqData.Description != nil && *reqData.Description != "" {
		updates["description"] = *reqData.Description
	}

	if reqData.Amount != nil && *reqData.Amount != "" {
		amount, err := strconv.ParseFloat(*reqData.Amount, 64)
		if err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": "Ungültiger Betrag"})
			return
		}
		updates["amount"] = amount
	}

	if reqData.Type != nil && *reqData.Type != "" {
		if *reqData.Type != "income" && *reqData.Type != "expense" {
			c.JSON(http.StatusBadRequest, gin.H{"error": "Ungültiger Transaktionstyp"})
			return
		}
		updates["type"] = *reqData.Type
	}

	if reqData.Date != nil && *reqData.Date != "" {
		date, err := time.Parse("2006-01-02", *reqData.Date)
		if err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": "Ungültiges Datum"})
			return
		}
		updates["date"] = date
	}

	if reqData.CategoryID != nil {
		if *reqData.CategoryID == "null" || *reqData.CategoryID == "" {
			updates["category_id"] = nil
		} else {
			categoryID, err := strconv.ParseUint(*reqData.CategoryID, 10, 32)
			if err != nil {
				c.JSON(http.StatusBadRequest, gin.H{"error": "Ungültige Kategorie-ID"})
				return
			}
			updates["category_id"] = uint(categoryID)
		}
	}

	if reqData.BankAccountID != nil {
		if *reqData.BankAccountID == "null" || *reqData.BankAccountID == "" {
			updates["bank_account_id"] = nil
		} else {
			bankAccountID, err := strconv.ParseUint(*reqData.BankAccountID, 10, 32)
			if err != nil {
				c.JSON(http.StatusBadRequest, gin.H{"error": "Ungültige Konto-ID"})
				return
			}
			bankID := uint(bankAccountID)
			updates["bank_account_id"] = &bankID
		}
	}

	if len(updates) == 0 {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Keine Änderungen angegeben"})
		return
	}

	// Transaktionen aktualisieren
	result := h.DB.Model(&models.Transaction{}).
		Where("id IN ? AND user_id = ?", reqData.TransactionIDs, userID).
		Updates(updates)

	if result.Error != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Fehler beim Aktualisieren der Transaktionen"})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"success": true,
		"updated": result.RowsAffected,
	})
}

// MultiDeleteTransactions löscht mehrere Transaktionen gleichzeitig
func (h *Handler) MultiDeleteTransactions(c *gin.Context) {
	// Session überprüfen
	session, _ := h.Store.Get(c.Request, "user-session")
	userID, ok := session.Values["user_id"]
	if !ok {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "Nicht angemeldet"})
		return
	}

	// JSON Request parsen
	var reqData struct {
		TransactionIDs []string `json:"transaction_ids"`
	}

	if err := c.ShouldBindJSON(&reqData); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Ungültige Anfrage"})
		return
	}

	if len(reqData.TransactionIDs) == 0 {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Keine Transaktionen ausgewählt"})
		return
	}

	// Transaktionen löschen (nur die des angemeldeten Users)
	result := h.DB.Where("id IN ? AND user_id = ?", reqData.TransactionIDs, userID).Delete(&models.Transaction{})

	if result.Error != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Fehler beim Löschen der Transaktionen"})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"success": true,
		"deleted": result.RowsAffected,
	})
}

// ToggleRecurrenceRule aktiviert/deaktiviert eine regelmäßige Transaktion
func (h *Handler) ToggleRecurrenceRule(c *gin.Context) {
	// Session überprüfen
	session, _ := h.Store.Get(c.Request, "user-session")
	userID, ok := session.Values["user_id"]
	if !ok {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "Nicht angemeldet"})
		return
	}

	// RecurrenceRule ID aus URL Parameter
	ruleIDStr := c.Param("id")
	ruleID, err := strconv.ParseUint(ruleIDStr, 10, 32)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Ungültige Regel-ID"})
		return
	}

	// Regel finden und Status umschalten
	var rule models.RecurrenceRule
	if err := h.DB.Where("id = ? AND user_id = ?", ruleID, userID).First(&rule).Error; err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "Regel nicht gefunden"})
		return
	}

	rule.IsActive = !rule.IsActive
	if err := h.DB.Save(&rule).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Fehler beim Speichern"})
		return
	}

	c.JSON(http.StatusOK, gin.H{"success": true, "is_active": rule.IsActive})
}

// generateTestData erstellt Testdaten für ein leeres Dashboard
func (h *Handler) generateTestData(userID uint) error {
	// Prüfen, ob bereits Transaktionen vorhanden sind
	var count int64
	h.DB.Model(&models.Transaction{}).Where("user_id = ?", userID).Count(&count)
	if count > 0 {
		return nil // Bereits Daten vorhanden
	}

	// Prüfen, ob bereits wiederkehrende Regeln vorhanden sind
	var ruleCount int64
	h.DB.Model(&models.RecurrenceRule{}).Where("user_id = ?", userID).Count(&ruleCount)
	if ruleCount > 0 {
		return nil // Bereits Regeln vorhanden
	}

	// Beispielkategorien erstellen
	categories := []models.Category{
		{UserID: userID, Name: "Gehalt", Description: "Monatliches Gehalt", Color: "#22c55e", Icon: "💰"},
		{UserID: userID, Name: "Lebensmittel", Description: "Einkäufe und Groceries", Color: "#f59e0b", Icon: "🛒"},
		{UserID: userID, Name: "Transport", Description: "ÖPNV, Benzin, etc.", Color: "#3b82f6", Icon: "🚗"},
		{UserID: userID, Name: "Unterhaltung", Description: "Kino, Restaurant, etc.", Color: "#8b5cf6", Icon: "🎬"},
		{UserID: userID, Name: "Miete", Description: "Wohnungsmiete", Color: "#ef4444", Icon: "🏠"},
	}

	for _, category := range categories {
		if err := h.DB.Create(&category).Error; err != nil {
			return err
		}
	}

	// Testdaten für die letzten 3 Monate generieren
	now := time.Now()
	transactions := []models.Transaction{}

	for i := 0; i < 90; i++ { // 90 Tage
		date := now.AddDate(0, 0, -i)
		
		// Gehalt am ersten des Monats
		if date.Day() == 1 {
			transactions = append(transactions, models.Transaction{
				UserID:      userID,
				Amount:      3500.0,
				Description: "Gehalt",
				Type:        "income",
				Date:        date,
				CategoryID:  &categories[0].ID,
			})
		}

		// Miete am 1. des Monats
		if date.Day() == 1 {
			transactions = append(transactions, models.Transaction{
				UserID:      userID,
				Amount:      1200.0,
				Description: "Wohnungsmiete",
				Type:        "expense",
				Date:        date,
				CategoryID:  &categories[4].ID,
			})
		}

		// Zufällige tägliche Ausgaben
		if i%3 == 0 { // Jeden 3. Tag
			// Lebensmittel
			transactions = append(transactions, models.Transaction{
				UserID:      userID,
				Amount:      float64(15 + (i%50)),
				Description: "Einkauf Supermarkt",
				Type:        "expense",
				Date:        date,
				CategoryID:  &categories[1].ID,
			})
		}

		if i%7 == 0 { // Wöchentlich
			// Transport
			transactions = append(transactions, models.Transaction{
				UserID:      userID,
				Amount:      float64(25 + (i%30)),
				Description: "ÖPNV Ticket",
				Type:        "expense",
				Date:        date,
				CategoryID:  &categories[2].ID,
			})
		}

		if i%10 == 0 { // Alle 10 Tage
			// Unterhaltung
			transactions = append(transactions, models.Transaction{
				UserID:      userID,
				Amount:      float64(40 + (i%60)),
				Description: "Restaurant / Kino",
				Type:        "expense",
				Date:        date,
				CategoryID:  &categories[3].ID,
			})
		}
	}

	// Alle Transaktionen in die Datenbank speichern
	for _, transaction := range transactions {
		if err := h.DB.Create(&transaction).Error; err != nil {
			return err
		}
	}

	// Wiederkehrende Transaktionen erstellen
	rules := []models.RecurrenceRule{
		{
			UserID:        userID,
			Amount:        3500.0,
			Description:   "Monatliches Gehalt",
			CategoryID:    &categories[0].ID,
			Type:          "income",
			Interval:      "monthly",
			IntervalCount: 1,
			StartDate:     time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location()),
			DayOfMonth:    intPtr(1),
			IsActive:      true,
		},
		{
			UserID:        userID,
			Amount:        1200.0,
			Description:   "Wohnungsmiete",
			CategoryID:    &categories[4].ID,
			Type:          "expense",
			Interval:      "monthly",
			IntervalCount: 1,
			StartDate:     time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location()),
			DayOfMonth:    intPtr(1),
			IsActive:      true,
		},
		{
			UserID:        userID,
			Amount:        80.0,
			Description:   "Wöchentlicher Einkauf",
			CategoryID:    &categories[1].ID,
			Type:          "expense",
			Interval:      "weekly",
			IntervalCount: 1,
			StartDate:     time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()),
			DayOfWeek:     intPtr(6), // Samstag
			IsActive:      true,
		},
	}

	// Wiederkehrende Regeln speichern
	for _, rule := range rules {
		if err := h.DB.Create(&rule).Error; err != nil {
			return err
		}
	}

	return nil
}

// intPtr gibt einen Pointer auf einen int zurück
func intPtr(i int) *int {
	return &i
}

// TestRecurringTransactions ist eine Test-Route für wiederkehrende Transaktionen
func (h *Handler) TestRecurringTransactions(c *gin.Context) {
	// Session überprüfen
	session, _ := h.Store.Get(c.Request, "user-session")
	userID, ok := session.Values["user_id"]
	if !ok {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "Nicht angemeldet"})
		return
	}

	// Wiederkehrende Transaktionen verarbeiten
	err := h.processRecurringTransactions(userID.(uint))
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	// Aktuelle Transaktionen abfragen
	var transactions []models.Transaction
	h.DB.Where("user_id = ? AND is_recurring = ?", userID, true).
		Preload("Category").
		Order("date DESC").
		Limit(20).
		Find(&transactions)

	c.JSON(http.StatusOK, gin.H{
		"message":              "Wiederkehrende Transaktionen verarbeitet",
		"recurring_transactions": transactions,
	})
}

// UpdateRecurrenceRule aktualisiert eine wiederkehrende Transaktion
func (h *Handler) UpdateRecurrenceRule(c *gin.Context) {
	// Session überprüfen
	session, _ := h.Store.Get(c.Request, "user-session")
	userID, ok := session.Values["user_id"]
	if !ok {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "Nicht angemeldet"})
		return
	}

	// RecurrenceRule ID aus URL Parameter
	ruleIDStr := c.Param("id")
	ruleID, err := strconv.ParseUint(ruleIDStr, 10, 32)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Ungültige Regel-ID"})
		return
	}

	// Existierende Regel laden
	var rule models.RecurrenceRule
	if err := h.DB.Where("id = ? AND user_id = ?", ruleID, userID).First(&rule).Error; err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "Regel nicht gefunden"})
		return
	}

	// Request Body parsen
	var updateData struct {
		Amount        *float64 `json:"amount"`
		Description   *string  `json:"description"`
		CategoryID    *uint    `json:"category_id"`
		Type          *string  `json:"type"`
		Interval      *string  `json:"interval"`
		IntervalCount *int     `json:"interval_count"`
		DayOfWeek     *int     `json:"day_of_week"`
		DayOfMonth    *int     `json:"day_of_month"`
		IsActive      *bool    `json:"is_active"`
		StartDate     *string  `json:"start_date"`
		EndDate       *string  `json:"end_date"`
	}

	if err := c.ShouldBindJSON(&updateData); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Ungültige Daten"})
		return
	}

	// Felder aktualisieren (nur wenn sie gesetzt sind)
	if updateData.Amount != nil {
		rule.Amount = *updateData.Amount
	}
	if updateData.Description != nil {
		rule.Description = *updateData.Description
	}
	if updateData.CategoryID != nil {
		rule.CategoryID = updateData.CategoryID
	}
	if updateData.Type != nil {
		rule.Type = *updateData.Type
	}
	if updateData.Interval != nil {
		rule.Interval = *updateData.Interval
	}
	if updateData.IntervalCount != nil {
		rule.IntervalCount = *updateData.IntervalCount
	}
	if updateData.DayOfWeek != nil {
		rule.DayOfWeek = updateData.DayOfWeek
	}
	if updateData.DayOfMonth != nil {
		rule.DayOfMonth = updateData.DayOfMonth
	}
	if updateData.IsActive != nil {
		rule.IsActive = *updateData.IsActive
	}
	if updateData.StartDate != nil {
		if startDate, err := time.Parse("2006-01-02", *updateData.StartDate); err == nil {
			rule.StartDate = startDate
		}
	}
	if updateData.EndDate != nil {
		if *updateData.EndDate == "" {
			rule.EndDate = nil
		} else {
			if endDate, err := time.Parse("2006-01-02", *updateData.EndDate); err == nil {
				rule.EndDate = &endDate
			}
		}
	}

	// Regel speichern
	if err := h.DB.Save(&rule).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Fehler beim Speichern"})
		return
	}

	// Aktualisierte Regel mit Kategorie laden
	h.DB.Preload("Category").First(&rule, rule.ID)

	c.JSON(http.StatusOK, gin.H{
		"success": true,
		"rule":    rule,
	})
}

// GetRecurrenceRules lädt alle wiederkehrenden Transaktionen eines Benutzers
func (h *Handler) GetRecurrenceRules(c *gin.Context) {
	// Session überprüfen
	session, _ := h.Store.Get(c.Request, "user-session")
	userID, ok := session.Values["user_id"]
	if !ok {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "Nicht angemeldet"})
		return
	}

	// Alle Regeln des Benutzers laden
	var rules []models.RecurrenceRule
	if err := h.DB.Where("user_id = ?", userID).
		Preload("Category").
		Order("created_at DESC").
		Find(&rules).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Fehler beim Laden der Regeln"})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"rules": rules,
	})
}

// DeleteRecurrenceRule löscht eine wiederkehrende Transaktion
func (h *Handler) DeleteRecurrenceRule(c *gin.Context) {
	// Session überprüfen
	session, _ := h.Store.Get(c.Request, "user-session")
	userID, ok := session.Values["user_id"]
	if !ok {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "Nicht angemeldet"})
		return
	}

	// RecurrenceRule ID aus URL Parameter
	ruleIDStr := c.Param("id")
	ruleID, err := strconv.ParseUint(ruleIDStr, 10, 32)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Ungültige Regel-ID"})
		return
	}

	// Regel löschen (nur wenn sie dem Benutzer gehört)
	result := h.DB.Where("id = ? AND user_id = ?", ruleID, userID).Delete(&models.RecurrenceRule{})
	if result.Error != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Fehler beim Löschen"})
		return
	}

	if result.RowsAffected == 0 {
		c.JSON(http.StatusNotFound, gin.H{"error": "Regel nicht gefunden"})
		return
	}

	c.JSON(http.StatusOK, gin.H{"success": true})
}

// processRecurringTransactions generiert alle fälligen wiederkehrenden Transaktionen
func (h *Handler) processRecurringTransactions(userID uint) error {
	// Alle aktiven Wiederholungsregeln für den Benutzer laden
	var rules []models.RecurrenceRule
	if err := h.DB.Where("user_id = ? AND is_active = ?", userID, true).Find(&rules).Error; err != nil {
		return err
	}

	// Für jede Regel prüfen, ob neue Transaktionen generiert werden müssen
	for _, rule := range rules {
		// Bis zu 10 Transaktionen pro Regel generieren (um Endlosschleifen zu vermeiden)
		for i := 0; i < 10; i++ {
			transaction, err := rule.GenerateTransaction(h.DB)
			if err != nil {
				// Fehler loggen, aber weitermachen
				fmt.Printf("Fehler beim Generieren einer wiederkehrenden Transaktion (Regel ID %d): %v\n", rule.ID, err)
				break
			}
			
			if transaction == nil {
				// Keine weitere Transaktion zu generieren
				break
			}
			
			fmt.Printf("Wiederkehrende Transaktion generiert: %s (€%.2f) für %s\n", 
				transaction.Description, transaction.Amount, transaction.Date.Format("02.01.2006"))
		}
	}

	return nil
}

// ShowRecurringTransactions zeigt die Verwaltungsseite für wiederkehrende Transaktionen
func (h *Handler) ShowRecurringTransactions(c *gin.Context) {
	// Session überprüfen
	session, _ := h.Store.Get(c.Request, "user-session")
	userID, ok := session.Values["user_id"]
	if !ok {
		c.Redirect(http.StatusSeeOther, "/login?error=required")
		return
	}

	// Benutzer aus der Datenbank laden
	var user models.User
	if err := h.DB.First(&user, userID).Error; err != nil {
		c.Redirect(http.StatusSeeOther, "/login?error=user_not_found")
		return
	}

	// Alle Regeln des Benutzers laden
	var rules []models.RecurrenceRule
	if err := h.DB.Where("user_id = ?", userID).
		Preload("Category").
		Order("created_at DESC").
		Find(&rules).Error; err != nil {
		c.String(http.StatusInternalServerError, "Fehler beim Laden der wiederkehrenden Transaktionen")
		return
	}

	// Template rendern
	component := views.RecurringTransactions(user.Name, rules)
	component.Render(c.Request.Context(), c.Writer)
}

// ShowSettings zeigt die Einstellungsseite an
func (h *Handler) ShowSettings(c *gin.Context) {
	// Session überprüfen
	session, _ := h.Store.Get(c.Request, "user-session")
	userID, ok := session.Values["user_id"]
	if !ok {
		c.Redirect(http.StatusSeeOther, "/login")
		return
	}

	// Benutzer laden
	var user models.User
	if err := h.DB.First(&user, userID).Error; err != nil {
		c.String(http.StatusInternalServerError, "Fehler beim Laden der Benutzerdaten")
		return
	}

	// Kategorien laden
	var categories []models.Category
	h.DB.Where("user_id = ?", userID).Find(&categories)

	// Bankkonten laden
	var bankAccounts []models.BankAccount
	h.DB.Where("user_id = ?", userID).Find(&bankAccounts)

	// Template rendern
	views.Settings(user.Name, user, categories, bankAccounts).Render(c.Request.Context(), c.Writer)
}

// UpdateUserSettings aktualisiert die Benutzereinstellungen
func (h *Handler) UpdateUserSettings(c *gin.Context) {
	// Session überprüfen
	session, _ := h.Store.Get(c.Request, "user-session")
	userID, ok := session.Values["user_id"]
	if !ok {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "Nicht angemeldet"})
		return
	}

	// JSON Body parsen
	var reqData struct {
		Username string `json:"username"`
	}

	if err := c.ShouldBindJSON(&reqData); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Ungültige Daten"})
		return
	}

	// Benutzer aktualisieren (nur Name, E-Mail bleibt unverändert)
	result := h.DB.Model(&models.User{}).Where("id = ?", userID).Update("name", reqData.Username)

	if result.Error != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Fehler beim Speichern"})
		return
	}

	c.JSON(http.StatusOK, gin.H{"success": true})
}

// UpdatePassword ändert das Benutzerpasswort
func (h *Handler) UpdatePassword(c *gin.Context) {
	// Session überprüfen
	session, _ := h.Store.Get(c.Request, "user-session")
	userID, ok := session.Values["user_id"]
	if !ok {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "Nicht angemeldet"})
		return
	}

	// JSON Body parsen
	var reqData struct {
		CurrentPassword string `json:"current_password"`
		NewPassword     string `json:"new_password"`
	}

	if err := c.ShouldBindJSON(&reqData); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Ungültige Daten"})
		return
	}

	// Benutzer laden
	var user models.User
	if err := h.DB.First(&user, userID).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Fehler beim Laden der Benutzerdaten"})
		return
	}

	// Aktuelles Passwort überprüfen
	if err := bcrypt.CompareHashAndPassword([]byte(user.PasswordHash), []byte(reqData.CurrentPassword)); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Aktuelles Passwort ist falsch"})
		return
	}

	// Neues Passwort hashen
	hashedPassword, err := bcrypt.GenerateFromPassword([]byte(reqData.NewPassword), bcrypt.DefaultCost)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Fehler beim Hashen des Passworts"})
		return
	}

	// Passwort aktualisieren
	result := h.DB.Model(&user).Update("password_hash", string(hashedPassword))
	if result.Error != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Fehler beim Speichern des Passworts"})
		return
	}

	c.JSON(http.StatusOK, gin.H{"success": true})
}

// CreateCategory erstellt eine neue Kategorie
func (h *Handler) CreateCategory(c *gin.Context) {
	// Session überprüfen
	session, _ := h.Store.Get(c.Request, "user-session")
	userID, ok := session.Values["user_id"]
	if !ok {
		c.Redirect(http.StatusSeeOther, "/login")
		return
	}

	// Form-Daten lesen
	name := c.PostForm("name")
	icon := c.PostForm("icon")
	color := c.PostForm("color")

	if name == "" || icon == "" {
		c.Redirect(http.StatusSeeOther, "/settings?error=invalid_data")
		return
	}

	// Kategorie erstellen
	category := models.Category{
		Name:   name,
		Icon:   icon,
		Color:  color,
		UserID: userID.(uint),
	}

	if err := h.DB.Create(&category).Error; err != nil {
		c.Redirect(http.StatusSeeOther, "/settings?error=create_failed")
		return
	}

	c.Redirect(http.StatusSeeOther, "/settings")
}

// DeleteCategory löscht eine Kategorie
func (h *Handler) DeleteCategory(c *gin.Context) {
	// Session überprüfen
	session, _ := h.Store.Get(c.Request, "user-session")
	userID, ok := session.Values["user_id"]
	if !ok {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "Nicht angemeldet"})
		return
	}

	// Category ID aus URL Parameter
	categoryIDStr := c.Param("id")
	categoryID, err := strconv.ParseUint(categoryIDStr, 10, 32)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Ungültige Kategorie-ID"})
		return
	}

	// Kategorie löschen (nur wenn sie dem Benutzer gehört)
	result := h.DB.Where("id = ? AND user_id = ?", categoryID, userID).Delete(&models.Category{})
	if result.Error != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Fehler beim Löschen"})
		return
	}

	if result.RowsAffected == 0 {
		c.JSON(http.StatusNotFound, gin.H{"error": "Kategorie nicht gefunden"})
		return
	}

	c.JSON(http.StatusOK, gin.H{"success": true})
}

// DeleteBankAccount löscht ein Bankkonto
func (h *Handler) DeleteBankAccount(c *gin.Context) {
	// Session überprüfen
	session, _ := h.Store.Get(c.Request, "user-session")
	userID, ok := session.Values["user_id"]
	if !ok {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "Nicht angemeldet"})
		return
	}

	// Account ID aus URL Parameter
	accountIDStr := c.Param("id")
	accountID, err := strconv.ParseUint(accountIDStr, 10, 32)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Ungültige Konto-ID"})
		return
	}

	// Konto löschen (nur wenn es dem Benutzer gehört)
	result := h.DB.Where("id = ? AND user_id = ?", accountID, userID).Delete(&models.BankAccount{})
	if result.Error != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Fehler beim Löschen"})
		return
	}

	if result.RowsAffected == 0 {
		c.JSON(http.StatusNotFound, gin.H{"error": "Konto nicht gefunden"})
		return
	}

	c.JSON(http.StatusOK, gin.H{"success": true})
}
