// monorepo/cloud/backend/internal/maplefile/service/collection/list_shared_with_user.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"
	dom_file "codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/internal/domain/file"
)

type ListSharedCollectionsService interface {
	Execute(ctx context.Context) (*CollectionsResponseDTO, error)
}

type listSharedCollectionsServiceImpl struct {
	config   *config.Configuration
	logger   *zap.Logger
	repo     dom_collection.CollectionRepository
	fileRepo dom_file.FileMetadataRepository
}

func NewListSharedCollectionsService(
	config *config.Configuration,
	logger *zap.Logger,
	repo dom_collection.CollectionRepository,
	fileRepo dom_file.FileMetadataRepository,
) ListSharedCollectionsService {
	logger = logger.Named("ListSharedCollectionsService")
	return &listSharedCollectionsServiceImpl{
		config:   config,
		logger:   logger,
		repo:     repo,
		fileRepo: fileRepo,
	}
}

func (svc *listSharedCollectionsServiceImpl) Execute(ctx context.Context) (*CollectionsResponseDTO, error) {
	//
	// STEP 1: 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, nil
	}

	svc.logger.Info("🔍 LIST SHARED COLLECTIONS: Starting",
		zap.String("user_id", userID.String()))

	//
	// STEP 2: Get collections shared with the user
	//
	collections, err := svc.repo.GetCollectionsSharedWithUser(ctx, userID)
	if err != nil {
		svc.logger.Error("🔍 LIST SHARED COLLECTIONS: Failed to get shared collections",
			zap.Any("error", err),
			zap.Any("user_id", userID))
		return nil, err
	}

	svc.logger.Info("🔍 LIST SHARED COLLECTIONS: Query completed",
		zap.String("user_id", userID.String()),
		zap.Int("collections_found", len(collections)))

	//
	// STEP 3: Filter out collections where user is the owner
	// (Only show collections shared BY others, not collections user owns and shared with themselves)
	//
	var sharedByOthers []*dom_collection.Collection
	for _, collection := range collections {
		if collection.OwnerID != userID {
			sharedByOthers = append(sharedByOthers, collection)
			svc.logger.Debug("🔍 LIST SHARED COLLECTIONS: Including collection shared by another user",
				zap.String("collection_id", collection.ID.String()),
				zap.String("owner_id", collection.OwnerID.String()))
		} else {
			svc.logger.Debug("🔍 LIST SHARED COLLECTIONS: Excluding self-owned collection",
				zap.String("collection_id", collection.ID.String()),
				zap.String("owner_id", collection.OwnerID.String()))
		}
	}

	svc.logger.Info("🔍 LIST SHARED COLLECTIONS: Filtered collections",
		zap.Int("total_collections", len(collections)),
		zap.Int("shared_by_others", len(sharedByOthers)),
		zap.Int("excluded_self_owned", len(collections)-len(sharedByOthers)))

	//
	// STEP 4: Map domain models to response DTOs
	//
	response := &CollectionsResponseDTO{
		Collections: make([]*CollectionResponseDTO, len(sharedByOthers)),
	}

	for i, collection := range sharedByOthers {
		// Use the file count stored in the collection itself (no N+1 query)
		ownerEmail := getOwnerEmailFromMembers(collection)
		response.Collections[i] = mapCollectionToDTO(collection, int(collection.FileCount), ownerEmail)
	}

	svc.logger.Info("🔍 LIST SHARED COLLECTIONS: Completed successfully",
		zap.Int("count", len(sharedByOthers)),
		zap.String("user_id", userID.String()))

	return response, nil
}
