package page

import (
	"context"
	"fmt"

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

	domainsite "codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/internal/domain/site"
	"codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/pkg/search"
)

// SearchPagesUseCase handles page search functionality
type SearchPagesUseCase struct {
	siteRepo     domainsite.Repository
	searchClient *search.Client
	logger       *zap.Logger
}

// ProvideSearchPagesUseCase creates a new SearchPagesUseCase
func ProvideSearchPagesUseCase(
	siteRepo domainsite.Repository,
	searchClient *search.Client,
	logger *zap.Logger,
) *SearchPagesUseCase {
	return &SearchPagesUseCase{
		siteRepo:     siteRepo,
		searchClient: searchClient,
		logger:       logger,
	}
}

// SearchPagesInput is the input for searching pages
type SearchPagesInput struct {
	Query  string `json:"query"`
	Limit  int64  `json:"limit"`
	Offset int64  `json:"offset"`
	Filter string `json:"filter,omitempty"` // e.g., "status = publish AND post_type = post"
}

// SearchPagesOutput is the output after searching pages
type SearchPagesOutput struct {
	Hits             interface{} `json:"hits"` // meilisearch.Hits
	Query            string      `json:"query"`
	ProcessingTimeMs int64       `json:"processing_time_ms"`
	TotalHits        int64       `json:"total_hits"`
	Limit            int64       `json:"limit"`
	Offset           int64       `json:"offset"`
}

// Execute performs a search on the site's indexed pages
func (uc *SearchPagesUseCase) Execute(ctx context.Context, tenantID, siteID gocql.UUID, input *SearchPagesInput) (*SearchPagesOutput, error) {
	uc.logger.Info("executing search pages use case",
		zap.String("tenant_id", tenantID.String()),
		zap.String("site_id", siteID.String()),
		zap.String("query", input.Query))

	// Get site to validate and check quotas
	site, err := uc.siteRepo.GetByID(ctx, tenantID, siteID)
	if err != nil {
		uc.logger.Error("failed to get site", zap.Error(err))
		return nil, domainsite.ErrSiteNotFound
	}

	// Verify site is verified (skip for test mode)
	if site.RequiresVerification() && !site.IsVerified {
		uc.logger.Warn("site not verified", zap.String("site_id", siteID.String()))
		return nil, domainsite.ErrSiteNotVerified
	}

	// No quota checking - usage-based billing (anti-abuse via rate limiting only)

	// Set default limits if not provided
	limit := input.Limit
	if limit <= 0 || limit > 100 {
		limit = 20 // Default to 20 results
	}

	offset := input.Offset
	if offset < 0 {
		offset = 0
	}

	// Build search request
	searchReq := search.SearchRequest{
		Query:  input.Query,
		Limit:  limit,
		Offset: offset,
		Filter: input.Filter,
	}

	// If no filter provided, default to only published pages
	if searchReq.Filter == "" {
		searchReq.Filter = "status = publish"
	}

	// Perform search
	result, err := uc.searchClient.Search(siteID.String(), searchReq)
	if err != nil {
		uc.logger.Error("failed to search pages", zap.Error(err))
		return nil, fmt.Errorf("failed to search pages: %w", err)
	}

	// Increment search request count (for usage tracking/billing)
	site.IncrementSearchCount()
	uc.logger.Info("incremented search count",
		zap.String("site_id", siteID.String()),
		zap.Int64("new_count", site.SearchRequestsCount))

	if err := uc.siteRepo.UpdateUsage(ctx, site); err != nil {
		uc.logger.Error("failed to update search usage", zap.Error(err))
		// Don't fail the search, just log the error
	} else {
		uc.logger.Info("search usage updated successfully",
			zap.String("site_id", siteID.String()),
			zap.Int64("search_count", site.SearchRequestsCount))
	}

	uc.logger.Info("search completed successfully",
		zap.String("site_id", siteID.String()),
		zap.String("query", input.Query),
		zap.Int64("total_hits", result.TotalHits),
		zap.Int64("processing_time_ms", result.ProcessingTimeMs))

	return &SearchPagesOutput{
		Hits:             result.Hits,
		Query:            result.Query,
		ProcessingTimeMs: result.ProcessingTimeMs,
		TotalHits:        result.TotalHits,
		Limit:            result.Limit,
		Offset:           result.Offset,
	}, nil
}
