package plugin

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

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

	"codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/config/constants"
	pagedto "codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/internal/interface/http/dto/page"
	pageservice "codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/internal/service/page"
	pageusecase "codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/internal/usecase/page"
	"codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/pkg/httperror"
	"codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/pkg/httpresponse"
	"codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/pkg/httpvalidation"
)

// SyncPagesHandler handles page synchronization from WordPress plugin
type SyncPagesHandler struct {
	syncService pageservice.SyncPagesService
	logger      *zap.Logger
}

// ProvideSyncPagesHandler creates a new SyncPagesHandler
func ProvideSyncPagesHandler(
	syncService pageservice.SyncPagesService,
	logger *zap.Logger,
) *SyncPagesHandler {
	return &SyncPagesHandler{
		syncService: syncService,
		logger:      logger,
	}
}

// Handle handles the HTTP request for syncing pages
// This endpoint is protected by API key middleware
func (h *SyncPagesHandler) Handle(w http.ResponseWriter, r *http.Request) {
	// Get site information from context (populated by API key middleware)
	isAuthenticated, ok := r.Context().Value(constants.SiteIsAuthenticated).(bool)
	if !ok || !isAuthenticated {
		h.logger.Error("site not authenticated in context")
		httperror.ProblemUnauthorized(w, "Invalid API key")
		return
	}

	// Extract site ID and tenant ID from context
	siteIDStr, _ := r.Context().Value(constants.SiteID).(string)
	tenantIDStr, _ := r.Context().Value(constants.SiteTenantID).(string)

	h.logger.Info("sync pages request",
		zap.String("tenant_id", tenantIDStr),
		zap.String("site_id", siteIDStr))

	// Parse IDs
	tenantID, err := gocql.ParseUUID(tenantIDStr)
	if err != nil {
		h.logger.Error("invalid tenant ID format", zap.Error(err))
		httperror.ProblemBadRequest(w, "invalid tenant ID")
		return
	}

	siteID, err := gocql.ParseUUID(siteIDStr)
	if err != nil {
		h.logger.Error("invalid site ID format", zap.Error(err))
		httperror.ProblemBadRequest(w, "invalid site ID")
		return
	}

	// CWE-436: Validate Content-Type before parsing
	if err := httpvalidation.ValidateJSONContentType(r); err != nil {
		httperror.ProblemBadRequest(w, err.Error())
		return
	}

	// Parse request body
	var req pagedto.SyncRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		httperror.ProblemBadRequest(w, "invalid request body")
		return
	}

	// CWE-20: Comprehensive input validation
	if err := req.Validate(); err != nil {
		h.logger.Warn("sync pages request validation failed", zap.Error(err))
		httperror.ProblemBadRequest(w, err.Error())
		return
	}

	// Convert DTO to use case input
	pages := make([]pageusecase.SyncPageInput, len(req.Pages))
	for i, p := range req.Pages {
		pages[i] = pageusecase.SyncPageInput{
			PageID:      p.PageID,
			Title:       p.Title,
			Content:     p.Content,
			Excerpt:     p.Excerpt,
			URL:         p.URL,
			Status:      p.Status,
			PostType:    p.PostType,
			Author:      p.Author,
			PublishedAt: p.PublishedAt,
			ModifiedAt:  p.ModifiedAt,
		}
	}

	input := &pageusecase.SyncPagesInput{
		Pages: pages,
	}

	// Call service
	output, err := h.syncService.SyncPages(r.Context(), tenantID, siteID, input)
	if err != nil {
		h.logger.Error("failed to sync pages",
			zap.Error(err),
			zap.String("site_id", siteIDStr))

		// Check for specific errors
		if err.Error() == "site not found" {
			httperror.ProblemNotFound(w, "site not found")
			return
		}
		if err.Error() == "site is not verified" {
			httperror.ProblemForbidden(w, "site is not verified")
			return
		}

		httperror.ProblemInternalServerError(w, "failed to sync pages")
		return
	}

	// Map to response DTO
	response := pagedto.SyncResponse{
		SyncedCount:  output.SyncedCount,
		IndexedCount: output.IndexedCount,
		FailedPages:  output.FailedPages,
		Message:      output.Message,
	}

	h.logger.Info("pages synced successfully",
		zap.String("site_id", siteIDStr),
		zap.Int("synced_count", output.SyncedCount),
		zap.Int("indexed_count", output.IndexedCount))

	httpresponse.OK(w, response)
}
