package site

import (
	"net/http"

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

	"codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/config/constants"
	sitedto "codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/internal/interface/http/dto/site"
	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"
)

// GetHandler handles getting a site by ID
type GetHandler struct {
	service siteservice.GetSiteService
	logger  *zap.Logger
}

// ProvideGetHandler creates a new GetHandler
func ProvideGetHandler(service siteservice.GetSiteService, logger *zap.Logger) *GetHandler {
	return &GetHandler{
		service: service,
		logger:  logger,
	}
}

// Handle handles the HTTP request for getting a site by ID
// Requires JWT authentication and tenant context
func (h *GetHandler) 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
	if _, err := gocql.ParseUUID(siteIDStr); err != nil {
		httperror.ProblemBadRequest(w, "Invalid site ID format. Please provide a valid site ID.")
		return
	}

	// Call service
	input := &siteusecase.GetSiteInput{ID: siteIDStr}
	output, err := h.service.GetSite(r.Context(), tenantID, input)
	if err != nil {
		h.logger.Error("failed to get site",
			zap.Error(err),
			zap.String("site_id", siteIDStr),
			zap.String("tenant_id", tenantID.String()))
		httperror.ProblemNotFound(w, "The requested site could not be found. It may have been deleted or you may not have access to it.")
		return
	}

	// Map to response DTO
	response := sitedto.GetResponse{
		ID:                   output.Site.ID.String(),
		TenantID:             output.Site.TenantID.String(),
		Domain:               output.Site.Domain,
		SiteURL:              output.Site.SiteURL,
		APIKeyPrefix:         output.Site.APIKeyPrefix,
		APIKeyLastFour:       output.Site.APIKeyLastFour,
		Status:               output.Site.Status,
		IsVerified:           output.Site.IsVerified,
		SearchIndexName:      output.Site.SearchIndexName,
		TotalPagesIndexed:    output.Site.TotalPagesIndexed,
		LastIndexedAt:        output.Site.LastIndexedAt,
		PluginVersion:        output.Site.PluginVersion,
		StorageUsedBytes:     output.Site.StorageUsedBytes,
		SearchRequestsCount:  output.Site.SearchRequestsCount,
		MonthlyPagesIndexed:  output.Site.MonthlyPagesIndexed,
		LastResetAt:          output.Site.LastResetAt,
		Language:             output.Site.Language,
		Timezone:             output.Site.Timezone,
		Notes:                output.Site.Notes,
		CreatedAt:            output.Site.CreatedAt,
		UpdatedAt:            output.Site.UpdatedAt,
	}

	// Write response with pretty JSON
	httpresponse.OK(w, response)
}
