// codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/internal/service/blockedemail/create.go
package blockedemail

import (
	"context"
	"strings"

	"go.uber.org/zap"

	"github.com/gocql/gocql"
	"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/config"
	"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/config/constants"
	uc_blockedemail "codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/internal/usecase/blockedemail"
	uc_user "codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/internal/usecase/user"
	"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/pkg/httperror"
	"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/pkg/validation"
)

type CreateBlockedEmailService interface {
	Execute(ctx context.Context, req *CreateBlockedEmailRequestDTO) (*BlockedEmailResponseDTO, error)
}

type createBlockedEmailServiceImpl struct {
	config                    *config.Configuration
	logger                    *zap.Logger
	createBlockedEmailUseCase uc_blockedemail.CreateBlockedEmailUseCase
	userGetByEmailUseCase     uc_user.UserGetByEmailUseCase
}

func NewCreateBlockedEmailService(
	config *config.Configuration,
	logger *zap.Logger,
	createBlockedEmailUseCase uc_blockedemail.CreateBlockedEmailUseCase,
	userGetByEmailUseCase uc_user.UserGetByEmailUseCase,
) CreateBlockedEmailService {
	logger = logger.Named("CreateBlockedEmailService")
	return &createBlockedEmailServiceImpl{
		config:                    config,
		logger:                    logger,
		createBlockedEmailUseCase: createBlockedEmailUseCase,
		userGetByEmailUseCase:     userGetByEmailUseCase,
	}
}

func (svc *createBlockedEmailServiceImpl) Execute(ctx context.Context, req *CreateBlockedEmailRequestDTO) (*BlockedEmailResponseDTO, error) {
	//
	// STEP 1: Validation
	//
	if req == nil {
		svc.logger.Warn("Failed validation with nil request")
		return nil, httperror.NewBadRequestError("Request is required")
	}

	e := make(map[string]string)
	if strings.TrimSpace(req.Email) == "" {
		e["email"] = "Email is required"
	}

	if len(e) != 0 {
		svc.logger.Warn("Failed validation",
			zap.Any("error", e))
		return nil, httperror.NewValidationError(e)
	}

	//
	// STEP 2: Get user ID from context
	//
	userID, ok := ctx.Value(constants.SessionUserID).(gocql.UUID)
	if !ok {
		svc.logger.Error("Failed getting user ID from context")
		return nil, httperror.NewInternalServerError("Authentication context error")
	}

	//
	// STEP 3: Check if blocked email belongs to a registered user
	//
	var blockedUserID gocql.UUID
	blockedUser, err := svc.userGetByEmailUseCase.Execute(ctx, req.Email)
	if err != nil {
		svc.logger.Debug("Blocked email user not found, continuing without user ID",
			zap.String("email", validation.MaskEmail(req.Email)),
			zap.Any("error", err))
		// User not found is fine - we still allow blocking non-existent emails
	} else if blockedUser != nil {
		blockedUserID = blockedUser.ID
	}

	//
	// STEP 4: Create blocked email
	//
	blockedEmail, err := svc.createBlockedEmailUseCase.Execute(ctx, userID, req.Email, blockedUserID, req.Reason)
	if err != nil {
		svc.logger.Error("Failed to create blocked email",
			zap.Any("error", err),
			zap.Any("user_id", userID),
			zap.String("email", validation.MaskEmail(req.Email)))
		return nil, err
	}

	//
	// STEP 5: Map to response DTO
	//
	response := &BlockedEmailResponseDTO{
		UserID:        blockedEmail.UserID,
		BlockedEmail:  blockedEmail.BlockedEmail,
		BlockedUserID: blockedEmail.BlockedUserID,
		Reason:        blockedEmail.Reason,
		CreatedAt:     blockedEmail.CreatedAt,
	}

	return response, nil
}
