package search

import (
	"log/slog"
	"net/http"
	"strings"

	"github.com/jackc/pgx/v5/pgxpool"

	"github.com/ultisuite/ulti-backend/internal/api/apiresponse"
	"github.com/ultisuite/ulti-backend/internal/api/apivalidate"
	"github.com/ultisuite/ulti-backend/internal/api/middleware"
	"github.com/ultisuite/ulti-backend/internal/api/query"
	"github.com/ultisuite/ulti-backend/internal/nextcloud"
)

type Handler struct {
	svc    *Service
	logger *slog.Logger
}

type Options struct {
	Nextcloud           *nextcloud.Client
	Engine              string
	MeilisearchURL      string
	MeilisearchKey      string
	MeilisearchIndex    string
	TypesenseURL        string
	TypesenseKey        string
	TypesenseCollection string
}

func NewHandler(db *pgxpool.Pool, opts Options) *Handler {
	return &Handler{
		svc: NewService(db, ServiceOptions{
			Nextcloud:           opts.Nextcloud,
			Engine:              opts.Engine,
			MeilisearchURL:      opts.MeilisearchURL,
			MeilisearchKey:      opts.MeilisearchKey,
			MeilisearchIndex:    opts.MeilisearchIndex,
			TypesenseURL:        opts.TypesenseURL,
			TypesenseKey:        opts.TypesenseKey,
			TypesenseCollection: opts.TypesenseCollection,
		}),
		logger: slog.Default().With("component", "search"),
	}
}

func (h *Handler) Search(w http.ResponseWriter, r *http.Request) {
	claims := middleware.ClaimsFromContext(r.Context())

	q := r.URL.Query().Get("q")
	if verr := validateSearchQuery(q); verr != nil {
		apiresponse.WriteError(w, r, http.StatusBadRequest, apiresponse.CodeInvalidQueryParam, "invalid query parameters", verr.Details)
		return
	}

	types := r.URL.Query().Get("types")
	if verr := validateSearchTypes(types); verr != nil {
		apiresponse.WriteError(w, r, http.StatusBadRequest, apiresponse.CodeInvalidQueryParam, "invalid query parameters", verr.Details)
		return
	}

	params, err := query.ParseListRequest(r)
	if err != nil {
		apivalidate.WriteQueryError(w, r, err)
		return
	}
	filters := SearchFilters{
		AccountID: strings.TrimSpace(r.URL.Query().Get("account_id")),
	}

	result, err := h.svc.Search(r.Context(), claims.Sub, q, types, params, filters)
	if err != nil {
		h.logger.Error("search", "error", err)
		apivalidate.WriteInternal(w, r)
		return
	}
	apiresponse.WriteJSON(w, http.StatusOK, result)
}
