package site

import (
	"net/http"

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

	"codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/config/constants"
	siteservice "codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/internal/service/site"
	siteusecase "codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/internal/usecase/site"
	"codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/pkg/httperror"
	"codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/pkg/httpresponse"
)

// VerifySiteHandler handles site verification HTTP requests
type VerifySiteHandler struct {
	service siteservice.VerifySiteService
	logger  *zap.Logger
}

// ProvideVerifySiteHandler creates a new VerifySiteHandler
func ProvideVerifySiteHandler(service siteservice.VerifySiteService, logger *zap.Logger) *VerifySiteHandler {
	return &VerifySiteHandler{
		service: service,
		logger:  logger,
	}
}

// VerifyResponse represents the verification response
// No request body needed - verification is done via DNS TXT record
type VerifyResponse struct {
	Success bool   `json:"success"`
	Status  string `json:"status"`
	Message string `json:"message"`
}

// contains checks if a string contains a substring (helper for error checking)
func contains(s, substr string) bool {
	return len(s) >= len(substr) && (s == substr || len(s) > len(substr) &&
		(s[:len(substr)] == substr || s[len(s)-len(substr):] == substr ||
		 findSubstring(s, substr)))
}

func findSubstring(s, substr string) bool {
	for i := 0; i <= len(s)-len(substr); i++ {
		if s[i:i+len(substr)] == substr {
			return true
		}
	}
	return false
}

// Handle handles the HTTP request for verifying a site
// Requires JWT authentication and tenant context
func (h *VerifySiteHandler) Handle(w http.ResponseWriter, r *http.Request) {
	// Get tenant ID from context
	tenantIDStr, ok := r.Context().Value(constants.ContextKeyTenantID).(string)
	if !ok {
		h.logger.Error("tenant ID not found in context")
		httperror.ProblemUnauthorized(w, "Tenant context is required to access this resource.")
		return
	}

	tenantID, err := gocql.ParseUUID(tenantIDStr)
	if err != nil {
		h.logger.Error("invalid tenant ID format", zap.Error(err))
		httperror.ProblemBadRequest(w, "Invalid tenant ID format. Please ensure you have a valid session.")
		return
	}

	// Get site ID from path parameter
	siteIDStr := r.PathValue("id")
	if siteIDStr == "" {
		httperror.ProblemBadRequest(w, "Site ID is required in the request path.")
		return
	}

	// Validate UUID format
	siteID, err := gocql.ParseUUID(siteIDStr)
	if err != nil {
		httperror.ProblemBadRequest(w, "Invalid site ID format. Please provide a valid site ID.")
		return
	}

	// No request body needed - DNS verification uses the token stored in the site entity
	// Call service with empty input
	input := &siteusecase.VerifySiteInput{}
	output, err := h.service.VerifySite(r.Context(), tenantID, siteID, input)
	if err != nil {
		h.logger.Error("failed to verify site",
			zap.Error(err),
			zap.String("site_id", siteIDStr),
			zap.String("tenant_id", tenantID.String()))

		// Check for specific error types
		errMsg := err.Error()

		if errMsg == "site not found" {
			httperror.ProblemNotFound(w, "The requested site could not be found. It may have been deleted or you may not have access to it.")
			return
		}

		// DNS-related errors
		if contains(errMsg, "DNS TXT record not found") {
			httperror.ProblemBadRequest(w, "DNS TXT record not found. Please add the verification record to your domain's DNS settings and wait 5-10 minutes for propagation.")
			return
		}
		if contains(errMsg, "DNS lookup timed out") {
			httperror.ProblemBadRequest(w, "DNS lookup timed out. Please check that your domain's DNS is properly configured.")
			return
		}
		if contains(errMsg, "domain not found") {
			httperror.ProblemBadRequest(w, "Domain not found. Please check that your domain is properly registered and DNS is active.")
			return
		}
		if contains(errMsg, "DNS verification failed") {
			httperror.ProblemBadRequest(w, "DNS verification failed. Please check your DNS settings and try again.")
			return
		}

		httperror.ProblemInternalServerError(w, "Failed to verify site. Please try again later.")
		return
	}

	// Map to response
	response := VerifyResponse{
		Success: output.Success,
		Status:  output.Status,
		Message: output.Message,
	}

	h.logger.Info("site verified successfully",
		zap.String("site_id", siteIDStr),
		zap.String("tenant_id", tenantID.String()))

	// Write response
	httpresponse.OK(w, response)
}
