// codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/internal/interface/http/tag/search_by_tags.go
package tag

import (
	"encoding/json"
	"net/http"
	"strconv"
	"strings"

	"github.com/gocql/gocql"
	"go.uber.org/zap"

	"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/config/constants"
	"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/internal/interface/http/middleware"
	svc_tag "codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/internal/service/tag"
	"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/pkg/httperror"
)

type SearchByTagsHandler struct {
	Service    *svc_tag.SearchByTagsService
	Logger     *zap.Logger
	middleware middleware.Middleware
}

func NewSearchByTagsHandler(
	service *svc_tag.SearchByTagsService,
	logger *zap.Logger,
	mid middleware.Middleware,
) *SearchByTagsHandler {
	return &SearchByTagsHandler{
		Service:    service,
		Logger:     logger,
		middleware: mid,
	}
}

func (h *SearchByTagsHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	h.middleware.Attach(h.Execute)(w, req)
}

func (h *SearchByTagsHandler) Execute(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()

	// Extract user ID from context (set by auth middleware)
	userID, ok := ctx.Value(constants.SessionUserID).(gocql.UUID)
	if !ok {
		httperror.ResponseError(w, httperror.NewUnauthorizedError("user not authenticated"))
		return
	}

	// Get tags parameter (required, comma-separated UUIDs)
	tagsParam := r.URL.Query().Get("tags")
	if tagsParam == "" {
		httperror.ResponseError(w, httperror.NewBadRequestError("tags parameter is required"))
		return
	}

	// Parse comma-separated tag IDs
	tagIDStrs := strings.Split(tagsParam, ",")
	if len(tagIDStrs) == 0 {
		httperror.ResponseError(w, httperror.NewBadRequestError("at least one tag ID is required"))
		return
	}

	tagIDs := make([]gocql.UUID, 0, len(tagIDStrs))
	for _, idStr := range tagIDStrs {
		id, err := gocql.ParseUUID(strings.TrimSpace(idStr))
		if err != nil {
			httperror.ResponseError(w, httperror.NewBadRequestError("invalid tag ID: "+idStr))
			return
		}
		tagIDs = append(tagIDs, id)
	}

	// Parse limit parameter
	limitStr := r.URL.Query().Get("limit")
	limit := 50 // default
	if limitStr != "" {
		if parsedLimit, err := strconv.Atoi(limitStr); err == nil && parsedLimit > 0 && parsedLimit <= 100 {
			limit = parsedLimit
		}
	}

	// Execute search
	result, err := h.Service.Execute(ctx, &svc_tag.SearchByTagsRequest{
		UserID: userID,
		TagIDs: tagIDs,
		Limit:  limit,
	})
	if err != nil {
		h.Logger.Error("failed to search by tags",
			zap.Int("tag_count", len(tagIDs)),
			zap.Error(err))
		httperror.ResponseError(w, httperror.NewInternalServerError("failed to search by tags"))
		return
	}

	// Return JSON response
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	json.NewEncoder(w).Encode(result)
}
