// monorepo/cloud/backend/internal/maplefile/service/collection/get.go
package collection

import (
	"context"

	"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"
	dom_collection "codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/internal/domain/collection"
	uc_collection "codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/internal/usecase/collection"
	"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/pkg/httperror"
)

type GetCollectionSyncDataService interface {
	Execute(ctx context.Context, userID gocql.UUID, cursor *dom_collection.CollectionSyncCursor, limit int64, accessType string) (*dom_collection.CollectionSyncResponse, error)
}

type getCollectionSyncDataServiceImpl struct {
	config                       *config.Configuration
	logger                       *zap.Logger
	getCollectionSyncDataUseCase uc_collection.GetCollectionSyncDataUseCase
}

func NewGetCollectionSyncDataService(
	config *config.Configuration,
	logger *zap.Logger,
	getCollectionSyncDataUseCase uc_collection.GetCollectionSyncDataUseCase,
) GetCollectionSyncDataService {
	logger = logger.Named("GetCollectionSyncDataService")
	return &getCollectionSyncDataServiceImpl{
		config:                       config,
		logger:                       logger,
		getCollectionSyncDataUseCase: getCollectionSyncDataUseCase,
	}
}

func (svc *getCollectionSyncDataServiceImpl) Execute(ctx context.Context, userID gocql.UUID, cursor *dom_collection.CollectionSyncCursor, limit int64, accessType string) (*dom_collection.CollectionSyncResponse, error) {
	//
	// STEP 1: Validation
	//
	if userID.String() == "" {
		svc.logger.Warn("Empty user ID provided")
		return nil, httperror.NewForBadRequestWithSingleField("user_id", "User ID is required")
	}

	//
	// STEP 2: Verify user ID from context matches the parameter
	//
	sessionUserID, ok := ctx.Value(constants.SessionUserID).(gocql.UUID)
	if !ok {
		svc.logger.Error("Failed getting user ID from context")
		return nil, httperror.NewForInternalServerErrorWithSingleField("message", "Authentication context error")
	}

	// Ensure the user can only get their own sync data
	if sessionUserID != userID {
		svc.logger.Warn("User trying to access another user's sync data",
			zap.Any("session_user_id", sessionUserID),
			zap.Any("requested_user_id", userID))
		return nil, httperror.NewForForbiddenWithSingleField("message", "Cannot access other user's sync data")
	}

	//
	// STEP 3: Get sync data based on access type
	//
	// Note: The use case will handle filtering collections based on the user's access
	// It returns only collections the user owns or has been granted access to
	syncData, err := svc.getCollectionSyncDataUseCase.Execute(ctx, userID, cursor, limit, accessType)
	if err != nil {
		svc.logger.Error("Failed to get collection sync data",
			zap.Any("error", err),
			zap.Any("user_id", userID))
		return nil, err
	}

	if syncData == nil {
		svc.logger.Debug("Collection sync data not found",
			zap.Any("user_id", userID))
		return nil, httperror.NewForNotFoundWithSingleField("message", "Collection sync results not found")
	}

	// Note: Access control is already handled by the use case
	// It only returns collections the user has access to
	// No need to check individual collection access here

	svc.logger.Debug("Collection sync data successfully retrieved",
		zap.Any("user_id", userID),
		zap.Int("collections_returned", len(syncData.Collections)))

	return syncData, nil
}
