package feeds

import (
	"fmt"
	"net/http"
	"strconv"

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

// Handler handles HTTP requests for feeds
type Handler struct {
	service *Service
}

// NewHandler creates a new feed handler
func NewHandler(service *Service) *Handler {
	return &Handler{service: service}
}

// RegisterRoutes registers the feed routes with the given router group
func (h *Handler) RegisterRoutes(router *gin.RouterGroup) {
	feeds := router.Group("/feeds")
	{
		feeds.GET("", h.handleListFeeds)
		feeds.POST("", h.handleAddFeed)
		feeds.GET("/:id", h.handleGetFeed)
		feeds.DELETE("/:id", h.handleDeleteFeed)
		feeds.POST("/:id/refresh", h.handleRefreshFeed)
		feeds.POST("/refresh", h.handleRefreshAllFeeds)
		feeds.POST("/import/opml", h.handleImportOPML)

		// Entry routes
		feeds.GET("/entries", h.handleListEntries)
		feeds.GET("/entries/:id", h.handleGetEntry)
		feeds.POST("/entries/:id/read", h.handleMarkEntryAsRead)
		feeds.POST("/entries/read-all", h.handleMarkAllAsRead)
		feeds.POST("/entries/:id/full-content", h.handleFetchFullContent)
	}

	// Test endpoint
	router.POST("/test/feeds/reset", h.handleReset)
}

// handleListFeeds handles GET /api/feeds
func (h *Handler) handleListFeeds(c *gin.Context) {
	feeds, err := h.service.GetFeeds()
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	c.JSON(http.StatusOK, feeds)
}

// handleAddFeed handles POST /api/feeds
func (h *Handler) handleAddFeed(c *gin.Context) {
	var req struct {
		URL string `json:"url" binding:"required"`
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	feed, err := h.service.AddFeed(req.URL)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, feed)
}

// handleGetFeed handles GET /api/feeds/:id
func (h *Handler) handleGetFeed(c *gin.Context) {
	id := c.Param("id")
	feed, err := h.service.GetFeed(id)
	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "Feed not found"})
		return
	}
	c.JSON(http.StatusOK, feed)
}

// handleDeleteFeed handles DELETE /api/feeds/:id
func (h *Handler) handleDeleteFeed(c *gin.Context) {
	id := c.Param("id")
	if err := h.service.DeleteFeed(id); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	c.Status(http.StatusOK)
}

// handleRefreshFeed handles POST /api/feeds/:id/refresh
func (h *Handler) handleRefreshFeed(c *gin.Context) {
	id := c.Param("id")
	if err := h.service.RefreshFeed(id); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	c.Status(http.StatusOK)
}

// handleRefreshAllFeeds handles POST /api/feeds/refresh
func (h *Handler) handleRefreshAllFeeds(c *gin.Context) {
	if err := h.service.RefreshAllFeeds(); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	c.Status(http.StatusOK)
}

// handleImportOPML handles POST /api/feeds/import
func (h *Handler) handleImportOPML(c *gin.Context) {
	file, _, err := c.Request.FormFile("file")
	if err != nil {
		// Check if URL is provided instead
		url := c.PostForm("url")
		if url != "" {
			resp, err := http.Get(url)
			if err != nil {
				c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("Failed to download OPML: %v", err)})
				return
			}
			defer func() {
				if err := resp.Body.Close(); err != nil {
					fmt.Printf("Error closing response body: %v\n", err)
				}
			}()

			feeds, err := h.service.ImportOPML(resp.Body)
			if err != nil {
				c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
				return
			}
			c.JSON(http.StatusOK, gin.H{"imported": len(feeds)})
			return
		}

		c.JSON(http.StatusBadRequest, gin.H{"error": "No file or URL provided"})
		return
	}
	defer func() {
		if err := file.Close(); err != nil {
			fmt.Printf("Error closing file: %v\n", err)
		}
	}()

	feeds, err := h.service.ImportOPML(file)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{"imported": len(feeds)})
}

// handleListEntries handles GET /api/feeds/entries
func (h *Handler) handleListEntries(c *gin.Context) {
	feedID := c.Query("feedId")
	unreadOnly, _ := strconv.ParseBool(c.Query("unreadOnly"))

	entries, err := h.service.GetEntries(feedID, unreadOnly)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, entries)
}

// handleGetEntry handles GET /api/feeds/entries/:id
func (h *Handler) handleGetEntry(c *gin.Context) {
	id := c.Param("id")
	entry, err := h.service.GetEntry(id)
	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "Entry not found"})
		return
	}
	c.JSON(http.StatusOK, entry)
}

// handleMarkEntryAsRead handles POST /api/feeds/entries/:id/read
func (h *Handler) handleMarkEntryAsRead(c *gin.Context) {
	id := c.Param("id")
	if err := h.service.MarkEntryAsRead(id); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	c.Status(http.StatusOK)
}

// handleFetchFullContent handles POST /api/feeds/entries/:id/full-content
func (h *Handler) handleFetchFullContent(c *gin.Context) {
	id := c.Param("id")
	if err := h.service.FetchFullContent(id); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	// Get the updated entry
	entry, err := h.service.GetEntry(id)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, entry)
}

// handleReset handles POST /api/test/feeds/reset
func (h *Handler) handleReset(c *gin.Context) {
	// Delete all entries
	if err := h.service.db.Exec("DELETE FROM entries").Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	// Delete all feeds
	if err := h.service.db.Exec("DELETE FROM feeds").Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.Status(http.StatusOK)
}

func (h *Handler) handleMarkAllAsRead(c *gin.Context) {
	feedID := c.Query("feedId")

	var err error
	if feedID != "" {
		// Mark all entries as read for a specific feed
		err = h.service.MarkAllEntriesAsRead(feedID)
	} else {
		// Mark all entries as read across all feeds
		err = h.service.MarkAllEntriesAsRead("")
	}

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

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