package plugin

import (
	"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"
)

// SyncStatusHandler handles sync status requests from WordPress plugin
type SyncStatusHandler struct {
	statusService pageservice.SyncStatusService
	logger        *zap.Logger
}

// ProvideSyncStatusHandler creates a new SyncStatusHandler
func ProvideSyncStatusHandler(
	statusService pageservice.SyncStatusService,
	logger *zap.Logger,
) *SyncStatusHandler {
	return &SyncStatusHandler{
		statusService: statusService,
		logger:        logger,
	}
}

// Handle handles the HTTP request for getting sync status
// This endpoint is protected by API key middleware
func (h *SyncStatusHandler) 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 status 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
	}

	// Call service
	output, err := h.statusService.GetSyncStatus(r.Context(), tenantID, siteID)
	if err != nil {
		h.logger.Error("failed to get sync status",
			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 get sync status")
		return
	}

	// Map to response DTO
	response := pagedto.StatusResponse{
		SiteID:              output.SiteID,
		TotalPages:          output.TotalPages,
		PublishedPages:      output.PublishedPages,
		DraftPages:          output.DraftPages,
		LastSyncedAt:        output.LastSyncedAt,
		PagesIndexedMonth:   output.PagesIndexedMonth,
		SearchRequestsMonth: output.SearchRequestsMonth,
		LastResetAt:         output.LastResetAt,
		SearchIndexStatus:   output.SearchIndexStatus,
		SearchIndexDocCount: output.SearchIndexDocCount,
	}

	h.logger.Info("sync status retrieved successfully",
		zap.String("site_id", siteIDStr),
		zap.Int64("total_pages", output.TotalPages))

	httpresponse.OK(w, response)
}

// HandleGetPageDetails handles the HTTP request for getting page details
func (h *SyncStatusHandler) HandleGetPageDetails(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)

	// Get page ID from URL path parameter
	pageID := r.PathValue("page_id")

	h.logger.Info("get page details request",
		zap.String("tenant_id", tenantIDStr),
		zap.String("site_id", siteIDStr),
		zap.String("page_id", pageID))

	// 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
	}

	// Validate page ID
	if pageID == "" {
		httperror.ProblemBadRequest(w, "page_id is required")
		return
	}

	// Call service
	input := &pageusecase.GetPageDetailsInput{
		PageID: pageID,
	}

	output, err := h.statusService.GetPageDetails(r.Context(), tenantID, siteID, input)
	if err != nil {
		h.logger.Error("failed to get page details",
			zap.Error(err),
			zap.String("site_id", siteIDStr),
			zap.String("page_id", pageID))

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

		httperror.ProblemInternalServerError(w, "failed to get page details")
		return
	}

	// Map to response DTO
	response := pagedto.PageDetailsResponse{
		PageID:           output.PageID,
		Title:            output.Title,
		Excerpt:          output.Excerpt,
		URL:              output.URL,
		Status:           output.Status,
		PostType:         output.PostType,
		Author:           output.Author,
		PublishedAt:      output.PublishedAt,
		ModifiedAt:       output.ModifiedAt,
		IndexedAt:        output.IndexedAt,
		MeilisearchDocID: output.MeilisearchDocID,
		IsIndexed:        output.IsIndexed,
	}

	h.logger.Info("page details retrieved successfully",
		zap.String("site_id", siteIDStr),
		zap.String("page_id", pageID))

	httpresponse.OK(w, response)
}
