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

import (
	"context"
	"errors"

	"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 CollectionsResponseDTO struct {
	Collections []*CollectionResponseDTO `json:"collections"`
}

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

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

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

func (svc *listUserCollectionsServiceImpl) 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, errors.New("user ID not found in context")
	}

	//
	// STEP 2: Get user's owned collections from repository
	//
	filterResult, err := svc.repo.GetCollectionsWithFilter(ctx, dom_collection.CollectionFilterOptions{
		UserID:        userID,
		IncludeOwned:  true,
		IncludeShared: false, // Only include owned collections for "My Folders"
	})
	if err != nil {
		svc.logger.Error("Failed to get user collections",
			zap.Any("error", err),
			zap.Any("user_id", userID))
		return nil, err
	}

	collections := filterResult.GetAllCollections()

	//
	// STEP 3: Deduplicate collections (user might be both owner and member)
	//
	seen := make(map[string]bool)
	uniqueCollections := make([]*dom_collection.Collection, 0, len(collections))
	for _, collection := range collections {
		collectionIDStr := collection.ID.String()
		if !seen[collectionIDStr] {
			seen[collectionIDStr] = true
			uniqueCollections = append(uniqueCollections, collection)
		}
	}

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

	for i, collection := range uniqueCollections {
		// 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.Debug("Retrieved user collections",
		zap.Int("total_count", len(collections)),
		zap.Int("unique_count", len(uniqueCollections)),
		zap.Any("user_id", userID))

	return response, nil
}
