package api

import (
	"database/sql"
	"fmt"
	"log"
	"net/http"
	"strings"
	"time"

	"pinepods/gpodder-api/internal/db"
	"pinepods/gpodder-api/internal/models"

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

// ValidDeviceTypes contains the allowed device types according to the gpodder API
var ValidDeviceTypes = map[string]bool{
	"desktop": true,
	"laptop":  true,
	"mobile":  true,
	"server":  true,
	"other":   true,
}

func listDevices(database *db.Database) gin.HandlerFunc {
	return func(c *gin.Context) {
		log.Printf("[DEBUG] listDevices handling request: %s %s", c.Request.Method, c.Request.URL.Path)

		// Log headers for debugging
		headers := c.Request.Header
		for name, values := range headers {
			for _, value := range values {
				log.Printf("[DEBUG] Header: %s: %s", name, value)
			}
		}

		// Log cookies
		cookies := c.Request.Cookies()
		for _, cookie := range cookies {
			log.Printf("[DEBUG] Cookie: %s: %s", cookie.Name, cookie.Value)
		}

		// Get user ID from context
		userID, exists := c.Get("userID")
		if !exists {
			log.Printf("[ERROR] listDevices: userID not found in context")
			c.JSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"})
			return
		}

		// Fix for the listDevices function
		// Replace the query code in listDevices function with this:

		log.Printf("[DEBUG] listDevices: Querying devices for userID: %v", userID)

		var query string
		var rows *sql.Rows
		var err error

		// Format query according to database type
		if database.IsPostgreSQLDB() {
			query = `
		        SELECT d.DeviceID, d.DeviceName, d.DeviceType,
		               COALESCE(d.DeviceCaption, '') as DeviceCaption, d.IsActive,
		               COALESCE(
		                   (SELECT COUNT(p.PodcastID)
		                    FROM "Podcasts" p
		                    WHERE p.UserID = $1),
		                   0
		               ) as subscription_count
		        FROM "GpodderDevices" d
		        WHERE d.UserID = $1 AND d.IsActive = true
		    `
			rows, err = database.Query(query, userID)
		} else {
			query = `
		        SELECT d.DeviceID, d.DeviceName, d.DeviceType,
		               COALESCE(d.DeviceCaption, '') as DeviceCaption, d.IsActive,
		               COALESCE(
		                   (SELECT COUNT(p.PodcastID)
		                    FROM Podcasts p
		                    WHERE p.UserID = ?),
		                   0
		               ) as subscription_count
		        FROM GpodderDevices d
		        WHERE d.UserID = ? AND d.IsActive = true
		    `
			rows, err = database.Query(query, userID, userID) // Note: passing userID twice for MySQL
		}

		if err != nil {
			log.Printf("[ERROR] listDevices: Error querying devices: %v", err)
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get devices"})
			return
		}
		defer rows.Close()

		var devices []models.GpodderDevice
		for rows.Next() {
			var device models.GpodderDevice
			var isActive bool

			if err := rows.Scan(
				&device.DeviceID,
				&device.DeviceName,
				&device.DeviceType,
				&device.DeviceCaption,
				&isActive,
				&device.Subscriptions,
			); err != nil {
				log.Printf("[ERROR] listDevices: Error scanning device row: %v", err)
				continue // Continue instead of returning to try to get at least some devices
			}

			// Only add active devices
			if isActive {
				log.Printf("[DEBUG] listDevices: Found active device: %s (ID: %d)",
					device.DeviceName, device.DeviceID)
				devices = append(devices, device)
			}
		}

		if err := rows.Err(); err != nil {
			log.Printf("[ERROR] listDevices: Error iterating device rows: %v", err)
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get devices"})
			return
		}

		// If no devices found, return empty array rather than error
		if len(devices) == 0 {
			log.Printf("[DEBUG] listDevices: No devices found for userID: %v", userID)
			c.JSON(http.StatusOK, []models.GpodderDevice{})
			return
		}

		log.Printf("[DEBUG] listDevices: Returning %d devices for userID: %v", len(devices), userID)

		// Return the list of devices
		c.JSON(http.StatusOK, devices)
	}
}

// updateDeviceData handles POST /api/2/devices/{username}/{deviceid}.json
func updateDeviceData(database *db.Database) gin.HandlerFunc {
	return func(c *gin.Context) {
		log.Printf("[DEBUG] updateDeviceData handling request: %s %s", c.Request.Method, c.Request.URL.Path)

		// Get user ID from context (set by AuthMiddleware)
		userID, exists := c.Get("userID")
		if !exists {
			log.Printf("[ERROR] updateDeviceData: userID not found in context")
			c.JSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"})
			return
		}

		// Get device name from URL with fix for .json suffix
		deviceName := c.Param("deviceid")
		// Also try alternative parameter name if needed
		if deviceName == "" {
			deviceName = c.Param("deviceid.json")
		}

		// Remove .json suffix if present
		if strings.HasSuffix(deviceName, ".json") {
			deviceName = strings.TrimSuffix(deviceName, ".json")
		}

		log.Printf("[DEBUG] updateDeviceData: Using device name: '%s'", deviceName)

		if deviceName == "" {
			log.Printf("[ERROR] updateDeviceData: Device ID is required")
			c.JSON(http.StatusBadRequest, gin.H{"error": "Device ID is required"})
			return
		}

		// Parse request body
		var req struct {
			Caption string `json:"caption"`
			Type    string `json:"type"`
		}

		if err := c.ShouldBindJSON(&req); err != nil {
			log.Printf("[ERROR] updateDeviceData: Error parsing request body: %v", err)
			c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body: expected a JSON object with 'caption' and 'type'"})
			return
		}

		log.Printf("[DEBUG] updateDeviceData: Device info - Name: %s, Caption: %s, Type: %s",
			deviceName, req.Caption, req.Type)

		// Validate device type if provided
		if req.Type != "" && !ValidDeviceTypes[req.Type] {
			log.Printf("[ERROR] updateDeviceData: Invalid device type: %s", req.Type)
			c.JSON(http.StatusBadRequest, gin.H{
				"error": fmt.Sprintf("Invalid device type: %s. Valid types are: desktop, laptop, mobile, server, other", req.Type),
			})
			return
		}

		// If type is empty, set to default 'other'
		if req.Type == "" {
			req.Type = "other"
		}

		// Begin transaction
		tx, err := database.Begin()
		if err != nil {
			log.Printf("[ERROR] updateDeviceData: Error beginning transaction: %v", err)
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to begin transaction"})
			return
		}

		defer func() {
			if err != nil {
				tx.Rollback()
			}
		}()

		// Check if device exists
		var deviceID int
		var query string

		log.Printf("[DEBUG] updateDeviceData: Checking if device exists - UserID: %v, DeviceName: %s", userID, deviceName)

		if database.IsPostgreSQLDB() {
			query = `SELECT DeviceID FROM "GpodderDevices" WHERE UserID = $1 AND DeviceName = $2`
		} else {
			query = `SELECT DeviceID FROM GpodderDevices WHERE UserID = ? AND DeviceName = ?`
		}

		err = tx.QueryRow(query, userID, deviceName).Scan(&deviceID)

		if err != nil {
			if err == sql.ErrNoRows {
				// Device doesn't exist, create it
				log.Printf("[DEBUG] updateDeviceData: Creating new device - UserID: %v, DeviceName: %s, Type: %s",
					userID, deviceName, req.Type)

				if database.IsPostgreSQLDB() {
					query = `INSERT INTO "GpodderDevices" (UserID, DeviceName, DeviceType, DeviceCaption, IsActive, LastSync)
                     VALUES ($1, $2, $3, $4, true, $5) RETURNING DeviceID`

					err = tx.QueryRow(query, userID, deviceName, req.Type, req.Caption, time.Now()).Scan(&deviceID)
					if err != nil {
						log.Printf("[ERROR] updateDeviceData: Error creating device: %v", err)
						c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create device"})
						return
					}
				} else {
					query = `INSERT INTO GpodderDevices (UserID, DeviceName, DeviceType, DeviceCaption, IsActive, LastSync)
                     VALUES (?, ?, ?, ?, true, ?)`

					result, err := tx.Exec(query, userID, deviceName, req.Type, req.Caption, time.Now())
					if err != nil {
						log.Printf("[ERROR] updateDeviceData: Error creating device: %v", err)
						c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create device"})
						return
					}

					// Get the last inserted ID
					lastID, err := result.LastInsertId()
					if err != nil {
						log.Printf("[ERROR] updateDeviceData: Error getting last insert ID: %v", err)
						c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get device ID"})
						return
					}

					deviceID = int(lastID)
				}

				log.Printf("[DEBUG] updateDeviceData: Created new device with ID: %d", deviceID)

				// Also create entry in device state table, handling both PostgreSQL and MySQL syntax
				if database.IsPostgreSQLDB() {
					query = `INSERT INTO "GpodderSyncDeviceState" (UserID, DeviceID)
                     VALUES ($1, $2) ON CONFLICT (UserID, DeviceID) DO NOTHING`
					_, err = tx.Exec(query, userID, deviceID)
				} else {
					// In MySQL, use INSERT IGNORE instead of ON CONFLICT
					query = `INSERT IGNORE INTO GpodderSyncDeviceState (UserID, DeviceID) VALUES (?, ?)`
					_, err = tx.Exec(query, userID, deviceID)
				}

				// Log the device state creation result but don't fail on error
				if err != nil {
					log.Printf("[WARNING] updateDeviceData: Error creating device state: %v", err)
					// Not fatal, continue with response
				}
			} else {
				log.Printf("[ERROR] updateDeviceData: Error checking device existence: %v", err)
				c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to check device"})
				return
			}
		} else {
			// Device exists, update it
			log.Printf("[DEBUG] updateDeviceData: Updating existing device with ID: %d", deviceID)

			if database.IsPostgreSQLDB() {
				query = `UPDATE "GpodderDevices" SET DeviceType = $1, DeviceCaption = $2, LastSync = $3, IsActive = true
                         WHERE DeviceID = $4`
			} else {
				query = `UPDATE GpodderDevices SET DeviceType = ?, DeviceCaption = ?, LastSync = ?, IsActive = true
                         WHERE DeviceID = ?`
			}

			_, err = tx.Exec(query, req.Type, req.Caption, time.Now(), deviceID)

			if err != nil {
				log.Printf("[ERROR] updateDeviceData: Error updating device: %v", err)
				c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update device"})
				return
			}
		}

		// Commit transaction
		if err = tx.Commit(); err != nil {
			log.Printf("[ERROR] updateDeviceData: Error committing transaction: %v", err)
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to commit changes"})
			return
		}

		// Return empty response with 200 status code as per gpodder API
		log.Printf("[DEBUG] updateDeviceData: Successfully processed device request")
		c.JSON(http.StatusOK, gin.H{})
	}
}

// getDeviceUpdates handles GET /api/2/updates/{username}/{deviceid}.json
func getDeviceUpdates(database *db.Database) gin.HandlerFunc {
	return func(c *gin.Context) {
		log.Printf("[DEBUG] getDeviceUpdates: Processing request: %s %s",
			c.Request.Method, c.Request.URL.Path)
		// Get user ID from context (set by AuthMiddleware)
		userID, exists := c.Get("userID")
		if !exists {
			c.JSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"})
			return
		}

		// Get device name from URL with fix for .json suffix
		deviceName := c.Param("deviceid")
		// Also try alternative parameter name if needed
		if deviceName == "" {
			deviceName = c.Param("deviceid.json")
		}

		// Remove .json suffix if present
		if strings.HasSuffix(deviceName, ".json") {
			deviceName = strings.TrimSuffix(deviceName, ".json")
		}

		log.Printf("[DEBUG] getDeviceUpdates: Using device name: '%s'", deviceName)

		// Parse query parameters
		sinceStr := c.Query("since")
		includeActions := c.Query("include_actions") == "true"

		var since int64 = 0
		if sinceStr != "" {
			_, err := fmt.Sscanf(sinceStr, "%d", &since)
			if err != nil {
				log.Printf("Invalid 'since' parameter: %s - %v", sinceStr, err)
				c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid 'since' parameter: must be a Unix timestamp"})
				return
			}
		}

		// Begin transaction
		tx, err := database.Begin()
		if err != nil {
			log.Printf("Error beginning transaction: %v", err)
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to begin transaction"})
			return
		}
		defer func() {
			if err != nil {
				tx.Rollback()
			}
		}()

		// Get or create the device
		var deviceID int
		var query string

		if database.IsPostgreSQLDB() {
			query = `
				SELECT DeviceID FROM "GpodderDevices"
				WHERE UserID = $1 AND DeviceName = $2 AND IsActive = true
			`
		} else {
			query = `
				SELECT DeviceID FROM GpodderDevices
				WHERE UserID = ? AND DeviceName = ? AND IsActive = true
			`
		}

		err = tx.QueryRow(query, userID, deviceName).Scan(&deviceID)

		if err != nil {
			if err == sql.ErrNoRows {
				// Device doesn't exist or is inactive, create it
				log.Printf("Creating new device for updates: %s", deviceName)

				if database.IsPostgreSQLDB() {
					query = `
						INSERT INTO "GpodderDevices" (UserID, DeviceName, DeviceType, IsActive, LastSync)
						VALUES ($1, $2, 'other', true, $3)
						RETURNING DeviceID
					`
					err = tx.QueryRow(query, userID, deviceName, time.Now()).Scan(&deviceID)
				} else {
					query = `
						INSERT INTO GpodderDevices (UserID, DeviceName, DeviceType, IsActive, LastSync)
						VALUES (?, ?, 'other', true, ?)
					`
					result, err := tx.Exec(query, userID, deviceName, time.Now())
					if err != nil {
						log.Printf("Error creating device: %v", err)
						c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create device"})
						return
					}

					lastID, err := result.LastInsertId()
					if err != nil {
						log.Printf("Error getting last insert ID: %v", err)
						c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get device ID"})
						return
					}

					deviceID = int(lastID)
				}

				if err != nil {
					log.Printf("Error creating device: %v", err)
					c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create device"})
					return
				}

				// Also create entry in device state table
				if database.IsPostgreSQLDB() {
					query = `
						INSERT INTO "GpodderSyncDeviceState" (UserID, DeviceID)
						VALUES ($1, $2)
						ON CONFLICT (UserID, DeviceID) DO NOTHING
					`
					_, err = tx.Exec(query, userID, deviceID)
				} else {
					query = `
						INSERT IGNORE INTO GpodderSyncDeviceState (UserID, DeviceID)
						VALUES (?, ?)
					`
					_, err = tx.Exec(query, userID, deviceID)
				}

				if err != nil {
					log.Printf("Error creating device state: %v", err)
					// Not fatal, continue
				}
			} else {
				log.Printf("Error getting device ID: %v", err)
				c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get device"})
				return
			}
		}

		// Get the current timestamp for the response
		timestamp := time.Now().Unix()

		// Build the response structure
		response := models.DeviceUpdateResponse{
			Add:       []models.Podcast{},
			Remove:    []string{},
			Updates:   []models.Episode{},
			Timestamp: timestamp,
		}

		// Only process updates if a since timestamp was provided
		if since > 0 {
			// Get the last sync timestamp for this device
			var lastSync int64

			if database.IsPostgreSQLDB() {
				query = `
					SELECT COALESCE(LastTimestamp, 0)
					FROM "GpodderSyncState"
					WHERE UserID = $1 AND DeviceID = $2
				`
			} else {
				query = `
					SELECT COALESCE(LastTimestamp, 0)
					FROM GpodderSyncState
					WHERE UserID = ? AND DeviceID = ?
				`
			}

			err = tx.QueryRow(query, userID, deviceID).Scan(&lastSync)

			if err != nil && err != sql.ErrNoRows {
				log.Printf("Error getting last sync timestamp: %v", err)
				c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get sync state"})
				return
			}

			// Handle podcasts to add (subscribed on other devices since the timestamp)
			var addRows *sql.Rows

			if database.IsPostgreSQLDB() {
				query = `
					SELECT DISTINCT p.FeedURL, p.PodcastName, p.Description, p.Author, p.ArtworkURL, p.WebsiteURL,
						  (SELECT COUNT(*) FROM "Podcasts" WHERE FeedURL = p.FeedURL) as subscribers
					FROM "Podcasts" p
					JOIN "GpodderSyncSubscriptions" s ON p.FeedURL = s.PodcastURL
					WHERE s.UserID = $1
					  AND s.DeviceID != $2
					  AND s.Timestamp > $3
					  AND s.Action = 'add'
					  AND NOT EXISTS (
						SELECT 1 FROM "GpodderSyncSubscriptions" s2
						WHERE s2.UserID = s.UserID
						  AND s2.PodcastURL = s.PodcastURL
						  AND s2.DeviceID = $2
						  AND s2.Timestamp > s.Timestamp
						  AND s2.Action = 'add'
					  )
				`
				addRows, err = tx.Query(query, userID, deviceID, since)
			} else {
				query = `
					SELECT DISTINCT p.FeedURL, p.PodcastName, p.Description, p.Author, p.ArtworkURL, p.WebsiteURL,
						  (SELECT COUNT(*) FROM Podcasts WHERE FeedURL = p.FeedURL) as subscribers
					FROM Podcasts p
					JOIN GpodderSyncSubscriptions s ON p.FeedURL = s.PodcastURL
					WHERE s.UserID = ?
					  AND s.DeviceID != ?
					  AND s.Timestamp > ?
					  AND s.Action = 'add'
					  AND NOT EXISTS (
						SELECT 1 FROM GpodderSyncSubscriptions s2
						WHERE s2.UserID = s.UserID
						  AND s2.PodcastURL = s.PodcastURL
						  AND s2.DeviceID = ?
						  AND s2.Timestamp > s.Timestamp
						  AND s2.Action = 'add'
					  )
				`
				addRows, err = tx.Query(query, userID, deviceID, since, deviceID) // Note: deviceID is used twice in MySQL
			}

			if err != nil {
				log.Printf("Error getting podcasts to add: %v", err)
				c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get updates"})
				return
			}
			defer addRows.Close()

			for addRows.Next() {
				var podcast models.Podcast
				var podcastName, description, author, artworkURL, websiteURL sql.NullString
				var subscribers int

				err := addRows.Scan(
					&podcast.URL,
					&podcastName,
					&description,
					&author,
					&artworkURL,
					&websiteURL,
					&subscribers,
				)
				if err != nil {
					log.Printf("Error scanning podcast row: %v", err)
					continue
				}

				// Set title - default to URL if name is null
				if podcastName.Valid && podcastName.String != "" {
					podcast.Title = podcastName.String
				} else {
					podcast.Title = podcast.URL
				}

				// Set optional fields if present
				if description.Valid {
					podcast.Description = description.String
				}
				if author.Valid {
					podcast.Author = author.String
				}
				if artworkURL.Valid {
					podcast.LogoURL = artworkURL.String
				}
				if websiteURL.Valid {
					podcast.Website = websiteURL.String
				}

				podcast.Subscribers = subscribers
				podcast.MygpoLink = fmt.Sprintf("/podcast/%s", podcast.URL)

				// Add the podcast to the response
				response.Add = append(response.Add, podcast)
			}

			if err = addRows.Err(); err != nil {
				log.Printf("Error iterating add rows: %v", err)
				// Continue processing other updates
			}

			// Query podcasts to remove (unsubscribed on other devices)
			var removeRows *sql.Rows

			if database.IsPostgreSQLDB() {
				query = `
					SELECT DISTINCT s.PodcastURL
					FROM "GpodderSyncSubscriptions" s
					WHERE s.UserID = $1
					  AND s.DeviceID != $2
					  AND s.Timestamp > $3
					  AND s.Action = 'remove'
					  AND NOT EXISTS (
						SELECT 1 FROM "GpodderSyncSubscriptions" s2
						WHERE s2.UserID = s.UserID
						  AND s2.PodcastURL = s.PodcastURL
						  AND s2.DeviceID = $2
						  AND s2.Timestamp > s.Timestamp
						  AND s2.Action = 'add'
					  )
				`
				removeRows, err = tx.Query(query, userID, deviceID, since)
			} else {
				query = `
					SELECT DISTINCT s.PodcastURL
					FROM GpodderSyncSubscriptions s
					WHERE s.UserID = ?
					  AND s.DeviceID != ?
					  AND s.Timestamp > ?
					  AND s.Action = 'remove'
					  AND NOT EXISTS (
						SELECT 1 FROM GpodderSyncSubscriptions s2
						WHERE s2.UserID = s.UserID
						  AND s2.PodcastURL = s.PodcastURL
						  AND s2.DeviceID = ?
						  AND s2.Timestamp > s.Timestamp
						  AND s2.Action = 'add'
					  )
				`
				removeRows, err = tx.Query(query, userID, deviceID, since, deviceID) // Note: deviceID is used twice
			}

			if err != nil {
				log.Printf("Error getting podcasts to remove: %v", err)
				c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get updates"})
				return
			}
			defer removeRows.Close()

			for removeRows.Next() {
				var podcastURL string
				err := removeRows.Scan(&podcastURL)
				if err != nil {
					log.Printf("Error scanning podcast URL: %v", err)
					continue
				}

				// Add the podcast URL to the response
				response.Remove = append(response.Remove, podcastURL)
			}

			if err = removeRows.Err(); err != nil {
				log.Printf("Error iterating remove rows: %v", err)
				// Continue processing other updates
			}

			// Query episode updates (if includeActions is true)
			if includeActions {
				var updateRows *sql.Rows

				if database.IsPostgreSQLDB() {
					query = `
						SELECT e.EpisodeTitle, e.EpisodeURL, p.PodcastName, p.FeedURL,
							   e.EpisodeDescription, e.EpisodeURL, e.EpisodePubDate,
							   a.Action, a.Position, a.Total, a.Started
						FROM "GpodderSyncEpisodeActions" a
						JOIN "Episodes" e ON a.EpisodeURL = e.EpisodeURL
						JOIN "Podcasts" p ON e.PodcastID = p.PodcastID
						WHERE a.UserID = $1
						  AND a.Timestamp > $2
						  AND a.Action != 'new'
						ORDER BY a.Timestamp DESC
					`
					updateRows, err = tx.Query(query, userID, since)
				} else {
					query = `
						SELECT e.EpisodeTitle, e.EpisodeURL, p.PodcastName, p.FeedURL,
							   e.EpisodeDescription, e.EpisodeURL, e.EpisodePubDate,
							   a.Action, a.Position, a.Total, a.Started
						FROM GpodderSyncEpisodeActions a
						JOIN Episodes e ON a.EpisodeURL = e.EpisodeURL
						JOIN Podcasts p ON e.PodcastID = p.PodcastID
						WHERE a.UserID = ?
						  AND a.Timestamp > ?
						  AND a.Action != 'new'
						ORDER BY a.Timestamp DESC
					`
					updateRows, err = tx.Query(query, userID, since)
				}

				if err != nil {
					log.Printf("Error getting episode updates: %v", err)
					c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get episode updates"})
					return
				}
				defer updateRows.Close()

				for updateRows.Next() {
					var episode models.Episode
					var pubDate time.Time
					var action string
					var position, total, started sql.NullInt64

					err := updateRows.Scan(
						&episode.Title,
						&episode.URL,
						&episode.PodcastTitle,
						&episode.PodcastURL,
						&episode.Description,
						&episode.Website,
						&pubDate,
						&action,
						&position,
						&total,
						&started,
					)
					if err != nil {
						log.Printf("Error scanning episode row: %v", err)
						continue
					}

					// Format the publication date in ISO 8601 format
					episode.Released = pubDate.Format(time.RFC3339)

					// Add the episode to the response
					response.Updates = append(response.Updates, episode)
				}

				if err = updateRows.Err(); err != nil {
					log.Printf("Error iterating episode update rows: %v", err)
					// Continue with other processing
				}
			}
		}

		// Update the last sync timestamp for this device
		if database.IsPostgreSQLDB() {
			query = `
				INSERT INTO "GpodderSyncState" (UserID, DeviceID, LastTimestamp)
				VALUES ($1, $2, $3)
				ON CONFLICT (UserID, DeviceID)
				DO UPDATE SET LastTimestamp = $3
			`
			_, err = tx.Exec(query, userID, deviceID, timestamp)
		} else {
			// MySQL uses INSERT ... ON DUPLICATE KEY UPDATE syntax
			query = `
				INSERT INTO GpodderSyncState (UserID, DeviceID, LastTimestamp)
				VALUES (?, ?, ?)
				ON DUPLICATE KEY UPDATE LastTimestamp = ?
			`
			_, err = tx.Exec(query, userID, deviceID, timestamp, timestamp)
		}

		if err != nil {
			log.Printf("Error updating device sync state: %v", err)
			// Not fatal, continue with response
		}

		// Update the device LastSync
		if database.IsPostgreSQLDB() {
			query = `
				UPDATE "GpodderDevices"
				SET LastSync = $1
				WHERE DeviceID = $2
			`
			_, err = tx.Exec(query, time.Now(), deviceID)
		} else {
			query = `
				UPDATE GpodderDevices
				SET LastSync = ?
				WHERE DeviceID = ?
			`
			_, err = tx.Exec(query, time.Now(), deviceID)
		}

		if err != nil {
			log.Printf("Error updating device last sync time: %v", err)
			// Non-critical error, continue
		}

		// Commit transaction
		if err = tx.Commit(); err != nil {
			log.Printf("Error committing transaction: %v", err)
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to commit changes"})
			return
		}

		// Return the response
		c.JSON(http.StatusOK, response)
	}
}

// deactivateDevice handles DELETE /api/2/devices/{username}/{deviceid}.json
// This is an extension to the gpodder API for device management
func deactivateDevice(database *db.PostgresDB) gin.HandlerFunc {
	return func(c *gin.Context) {
		// Get user ID from context (set by AuthMiddleware)
		userID, exists := c.Get("userID")
		if !exists {
			c.JSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"})
			return
		}

		// Get device name from URL
		// Get device name from URL with fix for .json suffix
		deviceName := c.Param("deviceid")
		// Also try alternative parameter name if needed
		if deviceName == "" {
			deviceName = c.Param("deviceid.json")
		}

		// Remove .json suffix if present
		if strings.HasSuffix(deviceName, ".json") {
			deviceName = strings.TrimSuffix(deviceName, ".json")
		}

		log.Printf("[DEBUG] deactivateDevice: Using device name: '%s'", deviceName)

		// Get the device ID
		var deviceID int
		err := database.QueryRow(`
			SELECT DeviceID FROM "GpodderDevices"
			WHERE UserID = $1 AND DeviceName = $2
		`, userID, deviceName).Scan(&deviceID)

		if err != nil {
			if err == sql.ErrNoRows {
				c.JSON(http.StatusNotFound, gin.H{"error": "Device not found"})
			} else {
				log.Printf("Error getting device ID: %v", err)
				c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get device"})
			}
			return
		}

		// Deactivate the device (rather than delete, to preserve history)
		_, err = database.Exec(`
			UPDATE "GpodderDevices"
			SET IsActive = false
			WHERE DeviceID = $1
		`, deviceID)

		if err != nil {
			log.Printf("Error deactivating device: %v", err)
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to deactivate device"})
			return
		}

		// Return success
		c.JSON(http.StatusOK, gin.H{
			"result":  "success",
			"message": "Device deactivated",
		})
	}
}

// renameDevice handles PUT /api/2/devices/{username}/{deviceid}/rename.json
// This is an extension to the gpodder API for device management
func renameDevice(database *db.PostgresDB) gin.HandlerFunc {
	return func(c *gin.Context) {
		// Get user ID from context (set by AuthMiddleware)
		userID, exists := c.Get("userID")
		if !exists {
			c.JSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"})
			return
		}

		// Get device name from URL
		oldDeviceName := c.Param("deviceid")
		if oldDeviceName == "" {
			c.JSON(http.StatusBadRequest, gin.H{"error": "Device ID is required"})
			return
		}

		// Parse request body
		var req struct {
			NewDeviceName string `json:"new_deviceid"`
		}
		if err := c.ShouldBindJSON(&req); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body: expected a JSON object with 'new_deviceid'"})
			return
		}

		if req.NewDeviceName == "" {
			c.JSON(http.StatusBadRequest, gin.H{"error": "New device ID is required"})
			return
		}

		// Check if the new device name already exists
		var existingCount int
		err := database.QueryRow(`
			SELECT COUNT(*) FROM "GpodderDevices"
			WHERE UserID = $1 AND DeviceName = $2 AND IsActive = true
		`, userID, req.NewDeviceName).Scan(&existingCount)

		if err != nil {
			log.Printf("Error checking for existing device: %v", err)
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to check for existing device"})
			return
		}

		if existingCount > 0 {
			c.JSON(http.StatusConflict, gin.H{"error": "Device with this name already exists"})
			return
		}

		// Update the device name
		result, err := database.Exec(`
			UPDATE "GpodderDevices"
			SET DeviceName = $1, LastSync = $2
			WHERE UserID = $3 AND DeviceName = $4 AND IsActive = true
		`, req.NewDeviceName, time.Now(), userID, oldDeviceName)

		if err != nil {
			log.Printf("Error renaming device: %v", err)
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to rename device"})
			return
		}

		rowsAffected, err := result.RowsAffected()
		if err != nil {
			log.Printf("Error getting rows affected: %v", err)
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get operation result"})
			return
		}

		if rowsAffected == 0 {
			c.JSON(http.StatusNotFound, gin.H{"error": "Device not found or not active"})
			return
		}

		// Return success
		c.JSON(http.StatusOK, gin.H{
			"result":  "success",
			"message": "Device renamed successfully",
		})
	}
}

// deviceSync represents the synchronization state of a device
type deviceSync struct {
	LastSync    time.Time `json:"last_sync"`
	DeviceID    int       `json:"-"`
	DeviceName  string    `json:"device_id"`
	DeviceType  string    `json:"device_type"`
	IsActive    bool      `json:"-"`
	SyncEnabled bool      `json:"sync_enabled"`
}

// getDeviceSyncStatus handles GET /api/2/devices/{username}/sync.json
// This is an extension to the gpodder API for device sync status
func getDeviceSyncStatus(database *db.PostgresDB) gin.HandlerFunc {
	return func(c *gin.Context) {
		// Get user ID from context (set by AuthMiddleware)
		userID, exists := c.Get("userID")
		if !exists {
			c.JSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"})
			return
		}

		// Query all devices and their sync status
		rows, err := database.Query(`
			SELECT d.DeviceID, d.DeviceName, d.DeviceType, d.LastSync, d.IsActive,
				   EXISTS (
					   SELECT 1 FROM "GpodderSyncDevicePairs" p
					   WHERE (p.DeviceID1 = d.DeviceID OR p.DeviceID2 = d.DeviceID)
						 AND p.UserID = d.UserID
				   ) as sync_enabled
			FROM "GpodderDevices" d
			WHERE d.UserID = $1
			ORDER BY d.LastSync DESC
		`, userID)

		if err != nil {
			log.Printf("Error querying device sync status: %v", err)
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get device sync status"})
			return
		}
		defer rows.Close()

		devices := make([]deviceSync, 0)
		for rows.Next() {
			var device deviceSync
			var lastSync sql.NullTime

			if err := rows.Scan(
				&device.DeviceID,
				&device.DeviceName,
				&device.DeviceType,
				&lastSync,
				&device.IsActive,
				&device.SyncEnabled,
			); err != nil {
				log.Printf("Error scanning device sync row: %v", err)
				continue
			}

			// Set the last sync time if valid
			if lastSync.Valid {
				device.LastSync = lastSync.Time
			}

			// Only include active devices
			if device.IsActive {
				devices = append(devices, device)
			}
		}

		if err = rows.Err(); err != nil {
			log.Printf("Error iterating device sync rows: %v", err)
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to process device sync status"})
			return
		}

		// Return the response
		c.JSON(http.StatusOK, gin.H{
			"devices":   devices,
			"timestamp": time.Now().Unix(),
		})
	}
}
