package router

import (
	"bookhoard/internal/database"
	"bookhoard/internal/handlers"
	"bookhoard/internal/services"
	"bookhoard/internal/utils"
	"bookhoard/templates"
	"bytes"
	"log"
	"net/http"
	"strconv"

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

func registerSearchRoutes(cfg *Config) {
	e := cfg.Echo
	// JWT middleware for protected routes
	jwtMiddleware := createJWTMiddleware(cfg)
	protected := e.Group("/api", jwtMiddleware)
	// Search endpoint - returns JSON or HTML based on HX-Request header
	protected.GET("/media-items/search", func(c *echo.Context) error {
		// Check if HTMX request (expects HTML)
		if c.Request().Header.Get("HX-Request") == "true" {
			return handleSearchHTML(c, cfg)
		}

		// Otherwise return JSON (API clients)
		return cfg.MediaHandler.SearchMediaItems(c)
	})
	protected.POST("/sync/books/query", cfg.MatchingHandler.QueryBooks)
}

// handleSearchHTML renders HTML response for HTMX requests
func handleSearchHTML(c *echo.Context, cfg *Config) error {
	user, ok := c.Get("user").(database.Users)
	if !ok {
		return c.String(http.StatusUnauthorized, "Unauthorized")
	}
	// Extract query parameters
	query := c.QueryParam("q")
	libraryID := c.QueryParam("library_id")
	limit, _ := strconv.Atoi(c.QueryParam("limit"))
	if limit == 0 {
		limit = 50
	}
	offset, _ := strconv.Atoi(c.QueryParam("offset"))
	// Validate library_id
	var libUUID pgtype.UUID
	if libraryID != "" {
		lib, err := uuid.Parse(libraryID)
		if err != nil {
			return c.String(http.StatusBadRequest, "invalid library_id")
		}
		libUUID = pgtype.UUID{Bytes: lib, Valid: true}
	} else {
		libUUID = pgtype.UUID{Valid: false}
	}
	// Extract filters
	authorFilter := c.QueryParam("author_filter")
	seriesFilter := c.QueryParam("series_filter")
	genreFilter := c.QueryParam("genre_filter")
	tagsFilter := c.QueryParam("tags_filter")
	languageFilter := c.QueryParam("language_filter")
	yearMin, _ := strconv.Atoi(c.QueryParam("year_min"))
	yearMax, _ := strconv.Atoi(c.QueryParam("year_max"))
	hasCover := false
	hasCoverValid := false
	if _, exists := c.QueryParams()["has_cover"]; exists {
		hasCover = c.QueryParam("has_cover") == "true"
		hasCoverValid = true
	}
	sortParam := c.QueryParam("sort")
	if sortParam == "" {
		sortParam = "title ASC"
	}
	// Build search params
	params := services.SearchParams{
		UserID:         user.ID,
		LibraryID:      libUUID,
		SearchQuery:    query,
		AuthorFilter:   authorFilter,
		SeriesFilter:   seriesFilter,
		GenreFilter:    genreFilter,
		TagsFilter:     tagsFilter,
		LanguageFilter: languageFilter,
		YearMin:        yearMin,
		YearMax:        yearMax,
		HasCover:       pgtype.Bool{Bool: hasCover, Valid: hasCoverValid},
		Sort:           sortParam,
		Limit:          limit,
		Offset:         offset,
	}
	// Execute search using handler method
	results, totalCount, err := cfg.MediaHandler.ExecuteSearch(c.Request().Context(), params)
	if err != nil {
		log.Printf("Search error: %v", err)
		return c.HTML(http.StatusInternalServerError, `<div style="color: red;">Search error</div>`)
	}
	// Convert to BookInfo
	bookInfoList := make([]handlers.BookInfo, len(results))
	for i, book := range results {
		bookUUID, _ := uuid.FromBytes(book.ID.Bytes[0:16])
		bookLibUUID, _ := uuid.FromBytes(book.LibraryID.Bytes[0:16])
		bookInfoList[i] = handlers.BookInfo{
			MediaItemID:    bookUUID.String(),
			Title:          book.Title,
			Author:         textToString(book.Author),
			CoverImagePath: utils.ResolveMediaURL(pgtype.UUID{Bytes: bookLibUUID, Valid: true}, book.CoverImagePath),
		}
	}
	// Stamp active conflict flags so cards route the play action correctly
	bookInfoList = handlers.MarkActiveConflicts(c.Request().Context(), cfg.Queries, user.ID, bookInfoList)
	// Render using BooksGrid template (or BookPickerGrid for collection picker)
	var buf bytes.Buffer
	if c.QueryParam("show_checkbox") == "true" {
		err = templates.BookPickerGrid(bookInfoList).Render(c.Request().Context(), &buf)
	} else {
		err = templates.BooksGrid(bookInfoList, limit, offset, totalCount, libraryID).Render(c.Request().Context(), &buf)
	}
	if err != nil {
		log.Printf("Template render error: %v", err)
		return c.HTML(http.StatusInternalServerError, `<div style="color: red;">Render error</div>`)
	}
	return c.HTML(http.StatusOK, buf.String())
}

// textToString converts pgtype.Text to string
func textToString(t pgtype.Text) string {
	if t.Valid {
		return t.String
	}
	return ""
}
