package handlers

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

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

type SeriesHandler struct {
	seriesService *services.SeriesService
}

func NewSeriesHandler(db *database.Queries) *SeriesHandler {
	return &SeriesHandler{
		seriesService: services.NewSeriesService(db),
	}
}

func (h *SeriesHandler) GetSeries(c *echo.Context) error {
	libraryID := c.QueryParam("library_id")
	var libUUID pgtype.UUID
	if libraryID != "" {
		parsed, err := uuid.Parse(libraryID)
		if err != nil {
			return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid library_id"})
		}
		libUUID = pgtype.UUID{Bytes: parsed, Valid: true}
	}

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

	seriesList, total, err := h.seriesService.GetSeriesPage(c.Request().Context(), libUUID, limit, offset)
	if err != nil {
		return c.JSON(http.StatusInternalServerError, map[string]string{"error": "Failed to load series"})
	}

	type SeriesResponse struct {
		Name          string   `json:"name"`
		BookCount     int64    `json:"book_count"`
		TotalInSeries int      `json:"total_in_series"`
		CoverPaths    []string `json:"cover_paths"`
		LastEntryAt   string   `json:"last_entry_at"`
	}

	response := make([]SeriesResponse, 0, len(seriesList))
	for _, s := range seriesList {
		response = append(response, SeriesResponse{
			Name:          s.Name,
			BookCount:     s.BookCount,
			TotalInSeries: s.TotalInSeries,
			CoverPaths:    s.CoverPaths,
			LastEntryAt:   s.LastEntryAt,
		})
	}

	return c.JSON(http.StatusOK, map[string]interface{}{
		"series": response,
		"total":  total,
		"limit":  limit,
		"offset": offset,
	})
}

func (h *SeriesHandler) GetSeriesBooks(c *echo.Context) error {
	seriesName := c.QueryParam("name")
	if seriesName == "" {
		return c.JSON(http.StatusBadRequest, map[string]string{"error": "name required"})
	}

	books, err := h.seriesService.GetSeriesBooks(c.Request().Context(), seriesName)
	if err != nil {
		return c.JSON(http.StatusInternalServerError, map[string]string{"error": "Failed to load series books"})
	}

	bookCards := make([]BookInfo, 0, len(books))
	for _, item := range books {
		itemUUID, _ := uuid.FromBytes(item.ID.Bytes[0:16])
		bookCards = append(bookCards, BookInfo{
			MediaItemID:    itemUUID.String(),
			Title:          item.Title,
			Author:         textToString(item.Author),
			CoverImagePath: utils.ResolveMediaURL(item.LibraryID, item.CoverImagePath),
		})
	}

	return c.JSON(http.StatusOK, map[string]interface{}{
		"name":  seriesName,
		"books": bookCards,
		"total": len(bookCards),
	})
}

func GetSeriesCardsData(ctx context.Context, db *database.Queries, libraryID pgtype.UUID, limit, offset int) ([]services.SeriesInfo, int, error) {
	svc := services.NewSeriesService(db)
	return svc.GetSeriesPage(ctx, libraryID, limit, offset)
}
