package handlers

import (
	"bookhoard/internal/database"
	"bookhoard/internal/services"
	"net/http"
	"strconv"

	"github.com/google/uuid"
	"github.com/jackc/pgx/v5/pgtype"
	"github.com/labstack/echo/v4"
)

type DashboardHandler struct {
	db               *database.Queries
	dashboardService *services.DashboardService
}

func NewDashboardHandler(db *database.Queries) *DashboardHandler {
	return &DashboardHandler{
		db:               db,
		dashboardService: services.NewDashboardService(db),
	}
}

func (h *DashboardHandler) GetSections(c echo.Context) error {
	user := c.Get("user").(database.Users)
	userUUID := uuid.UUID(user.ID.Bytes)

	libraryID := c.QueryParam("library_id")
	if libraryID == "" {
		return c.JSON(http.StatusBadRequest, map[string]string{"error": "library_id required"})
	}
	libUUID, err := uuid.Parse(libraryID)
	if err != nil {
		return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid library_id"})
	}

	prefs, _ := h.dashboardService.GetDashboardPreferences(c.Request().Context(), userUUID, libUUID)

	limit := 20
	if limitStr := c.QueryParam("limit"); limitStr != "" {
		if l, err := strconv.Atoi(limitStr); err == nil && l > 0 && l <= 100 {
			limit = l
		}
	}

	sections, err := h.dashboardService.GetDashboardSections(
		c.Request().Context(),
		userUUID,
		libUUID,
		limit,
		prefs.CollectionOrder,
		prefs.HiddenCollections,
	)
	if err != nil {
		return c.JSON(http.StatusInternalServerError, map[string]string{"error": "Failed to load dashboard sections"})
	}

	sectionData := BuildSections(sections)

	return c.JSON(http.StatusOK, map[string]interface{}{"sections": sectionData})
}

func (h *DashboardHandler) UpdatePreferences(c echo.Context) error {
	user := c.Get("user").(database.Users)
	userUUID := uuid.UUID(user.ID.Bytes)

	var req struct {
		LibraryID         string   `json:"library_id"`
		HiddenCollections []string `json:"hidden_collections"`
		CollectionOrder   []string `json:"collection_order"`
		ItemsPerSection   int      `json:"items_per_section"`
	}

	if err := c.Bind(&req); err != nil {
		return c.JSON(http.StatusBadRequest, map[string]string{"error": "Invalid request"})
	}

	libUUID, err := uuid.Parse(req.LibraryID)
	if err != nil {
		return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid library_id"})
	}

	prefs, err := h.dashboardService.UpsertDashboardPreferences(c.Request().Context(), database.UpsertDashboardPreferencesParams{
		UserID:            pgtype.UUID{Bytes: userUUID, Valid: true},
		LibraryID:         pgtype.UUID{Bytes: libUUID, Valid: true},
		HiddenCollections: req.HiddenCollections,
		CollectionOrder:   req.CollectionOrder,
		ItemsPerSection:   pgtype.Int4{Int32: int32(req.ItemsPerSection), Valid: true},
	})

	if err != nil {
		return c.JSON(http.StatusInternalServerError, map[string]string{"error": "Failed to save preferences"})
	}

	return c.JSON(http.StatusOK, prefs)
}

func (h *DashboardHandler) RestoreSystemCollection(c echo.Context) error {
	user := c.Get("user").(database.Users)
	userUUID := uuid.UUID(user.ID.Bytes)

	var req struct {
		CollectionName string `json:"collection_name"`
	}

	if err := c.Bind(&req); err != nil {
		return c.JSON(http.StatusBadRequest, map[string]string{"error": "Invalid request"})
	}

	if req.CollectionName == "" {
		return c.JSON(http.StatusBadRequest, map[string]string{"error": "collection_name required"})
	}

	validCollections := map[string]bool{
		"continue-reading": true,
		"recently-added":   true,
		"recently-read":    true,
		"not-started":      true,
	}
	if !validCollections[req.CollectionName] {
		return c.JSON(http.StatusBadRequest, map[string]string{"error": "Invalid system collection name"})
	}

	err := h.dashboardService.RestoreSystemCollection(c.Request().Context(), userUUID, req.CollectionName)
	if err != nil {
		return c.JSON(http.StatusInternalServerError, map[string]string{"error": "Failed to restore system collection"})
	}

	return c.JSON(http.StatusOK, map[string]string{"message": "System collection restored to defaults"})
}

func BuildSections(sections []services.DashboardSection) []SectionData {
	var result []SectionData

	for _, ds := range sections {
		bookCards := make([]BookInfo, len(ds.Items))
		for i, item := range ds.Items {
			itemUUID, _ := uuid.FromBytes(item.ID.Bytes[0:16])
			bookCards[i] = BookInfo{
				MediaItemID:    itemUUID.String(),
				Title:          item.Title,
				Author:         textToString(item.Author),
				CoverImagePath: textToString(item.CoverImagePath),
			}
		}

		result = append(result, SectionData{
			ID:          ds.CollectionName,
			IsSystem:    ds.IsSystem,
			Title:       ds.Title,
			Description: ds.Description,
			Icon:        ds.Icon,
			Items:       bookCards,
			ViewAllURL:  getViewAllURL(ds.CollectionName, ds.QueryType),
			Priority:    ds.Priority,
		})
	}

	return result
}

func getViewAllURL(key, queryType string) string {
	urls := map[string]string{
		"continue-reading": "/section/continue-reading",
		"recently-added":   "/section/recently-added",
		"recently-read":    "/history",
		"not-started":      "/section/not-started",
	}
	if url, exists := urls[queryType]; exists {
		return url
	}
	return ""
}
