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

// DeletePagesHandler handles page deletion from WordPress plugin
type DeletePagesHandler struct {
	deleteService pageservice.DeletePagesService
	logger        *zap.Logger
}

// ProvideDeletePagesHandler creates a new DeletePagesHandler
func ProvideDeletePagesHandler(
	deleteService pageservice.DeletePagesService,
	logger *zap.Logger,
) *DeletePagesHandler {
	return &DeletePagesHandler{
		deleteService: deleteService,
		logger:        logger,
	}
}

// Handle handles the HTTP request for deleting pages
// This endpoint is protected by API key middleware
func (h *DeletePagesHandler) 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("delete 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.DeleteRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		httperror.ProblemBadRequest(w, "invalid request body")
		return
	}

	// Validate request
	if len(req.PageIDs) == 0 {
		httperror.ProblemBadRequest(w, "page_ids array is required")
		return
	}

	// Convert DTO to use case input
	input := &pageusecase.DeletePagesInput{
		PageIDs: req.PageIDs,
	}

	// Call service
	output, err := h.deleteService.DeletePages(r.Context(), tenantID, siteID, input)
	if err != nil {
		h.logger.Error("failed to delete 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 delete pages")
		return
	}

	// Map to response DTO
	response := pagedto.DeleteResponse{
		DeletedCount:   output.DeletedCount,
		DeindexedCount: output.DeindexedCount,
		FailedPages:    output.FailedPages,
		Message:        output.Message,
	}

	h.logger.Info("pages deleted successfully",
		zap.String("site_id", siteIDStr),
		zap.Int("deleted_count", output.DeletedCount))

	httpresponse.OK(w, response)
}

// HandleDeleteAll handles the HTTP request for deleting all pages
func (h *DeletePagesHandler) HandleDeleteAll(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("delete all 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
	}

	// Call service
	output, err := h.deleteService.DeleteAllPages(r.Context(), tenantID, siteID)
	if err != nil {
		h.logger.Error("failed to delete all 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 delete all pages")
		return
	}

	// Map to response DTO
	response := pagedto.DeleteResponse{
		DeletedCount:   output.DeletedCount,
		DeindexedCount: output.DeindexedCount,
		Message:        output.Message,
	}

	h.logger.Info("all pages deleted successfully",
		zap.String("site_id", siteIDStr),
		zap.Int("deleted_count", output.DeletedCount))

	httpresponse.OK(w, response)
}
