// monorepo/cloud/maplefile-backend/internal/maplefile/usecase/collection/count_collections.go
package collection

import (
	"context"

	"go.uber.org/zap"

	"github.com/gocql/gocql"
	"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/config"
	dom_collection "codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/internal/domain/collection"
	"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/pkg/httperror"
)

// CountCollectionsResponse contains the collection counts for a user
type CountCollectionsResponse struct {
	OwnedCollections  int `json:"owned_collections"`
	SharedCollections int `json:"shared_collections"`
	TotalCollections  int `json:"total_collections"`
}

// CountFoldersResponse contains the folder counts for a user (folders only, not albums)
type CountFoldersResponse struct {
	OwnedFolders  int `json:"owned_folders"`
	SharedFolders int `json:"shared_folders"`
	TotalFolders  int `json:"total_folders"`
}

type CountUserCollectionsUseCase interface {
	Execute(ctx context.Context, userID gocql.UUID) (*CountCollectionsResponse, error)
}

// NEW: Use case specifically for counting folders only
type CountUserFoldersUseCase interface {
	Execute(ctx context.Context, userID gocql.UUID) (*CountFoldersResponse, error)
}

type countUserCollectionsUseCaseImpl struct {
	config *config.Configuration
	logger *zap.Logger
	repo   dom_collection.CollectionRepository
}

type countUserFoldersUseCaseImpl struct {
	config *config.Configuration
	logger *zap.Logger
	repo   dom_collection.CollectionRepository
}

func NewCountUserCollectionsUseCase(
	config *config.Configuration,
	logger *zap.Logger,
	repo dom_collection.CollectionRepository,
) CountUserCollectionsUseCase {
	logger = logger.Named("CountUserCollectionsUseCase")
	return &countUserCollectionsUseCaseImpl{config, logger, repo}
}

func NewCountUserFoldersUseCase(
	config *config.Configuration,
	logger *zap.Logger,
	repo dom_collection.CollectionRepository,
) CountUserFoldersUseCase {
	logger = logger.Named("CountUserFoldersUseCase")
	return &countUserFoldersUseCaseImpl{config, logger, repo}
}

func (uc *countUserCollectionsUseCaseImpl) Execute(ctx context.Context, userID gocql.UUID) (*CountCollectionsResponse, error) {
	//
	// STEP 1: Validation.
	//

	e := make(map[string]string)
	if userID.String() == "" {
		e["user_id"] = "User ID is required"
	}
	if len(e) != 0 {
		uc.logger.Warn("Failed validating count user collections",
			zap.Any("error", e))
		return nil, httperror.NewForBadRequest(&e)
	}

	//
	// STEP 2: Count collections.
	//

	ownedCollections, err := uc.repo.CountOwnedCollections(ctx, userID)
	if err != nil {
		uc.logger.Error("Failed to count owned collections",
			zap.String("user_id", userID.String()),
			zap.Error(err))
		return nil, err
	}

	sharedCollections, err := uc.repo.CountSharedCollections(ctx, userID)
	if err != nil {
		uc.logger.Error("Failed to count shared collections",
			zap.String("user_id", userID.String()),
			zap.Error(err))
		return nil, err
	}

	response := &CountCollectionsResponse{
		OwnedCollections:  ownedCollections,
		SharedCollections: sharedCollections,
		TotalCollections:  ownedCollections + sharedCollections,
	}

	uc.logger.Debug("Successfully counted user collections",
		zap.String("user_id", userID.String()),
		zap.Int("owned_collections", ownedCollections),
		zap.Int("shared_collections", sharedCollections),
		zap.Int("total_collections", response.TotalCollections))

	return response, nil
}

func (uc *countUserFoldersUseCaseImpl) Execute(ctx context.Context, userID gocql.UUID) (*CountFoldersResponse, error) {
	//
	// STEP 1: Validation.
	//

	e := make(map[string]string)
	if userID.String() == "" {
		e["user_id"] = "User ID is required"
	}
	if len(e) != 0 {
		uc.logger.Warn("Failed validating count user folders",
			zap.Any("error", e))
		return nil, httperror.NewForBadRequest(&e)
	}

	//
	// STEP 2: DEBUG - Check what's actually in the database
	//

	// ADD DEBUG LOGGING - Cast to concrete type to access debug method
	if debugRepo, ok := uc.repo.(interface {
		DebugCollectionRecords(context.Context, gocql.UUID) error
	}); ok {
		if debugErr := debugRepo.DebugCollectionRecords(ctx, userID); debugErr != nil {
			uc.logger.Warn("Failed to debug collection records", zap.Error(debugErr))
		}
	}

	//
	// STEP 3: Count folders with separate owned/shared counts AND total unique count
	//

	ownedFolders, err := uc.repo.CountOwnedFolders(ctx, userID)
	if err != nil {
		uc.logger.Error("Failed to count owned folders",
			zap.String("user_id", userID.String()),
			zap.Error(err))
		return nil, err
	}

	sharedFolders, err := uc.repo.CountSharedFolders(ctx, userID)
	if err != nil {
		uc.logger.Error("Failed to count shared folders",
			zap.String("user_id", userID.String()),
			zap.Error(err))
		return nil, err
	}

	// NEW: Get the deduplicated total count
	var totalUniqueFolders int
	if uniqueRepo, ok := uc.repo.(interface {
		CountTotalUniqueFolders(context.Context, gocql.UUID) (int, error)
	}); ok {
		totalUniqueFolders, err = uniqueRepo.CountTotalUniqueFolders(ctx, userID)
		if err != nil {
			uc.logger.Error("Failed to count unique total folders",
				zap.String("user_id", userID.String()),
				zap.Error(err))
			return nil, err
		}
	} else {
		// Fallback to simple addition if the method is not available
		uc.logger.Warn("CountTotalUniqueFolders method not available, using simple addition")
		totalUniqueFolders = ownedFolders + sharedFolders
	}

	response := &CountFoldersResponse{
		OwnedFolders:  ownedFolders,
		SharedFolders: sharedFolders,
		TotalFolders:  totalUniqueFolders, // Use deduplicated count
	}

	uc.logger.Info("Successfully counted user folders with deduplication",
		zap.String("user_id", userID.String()),
		zap.Int("owned_folders", ownedFolders),
		zap.Int("shared_folders", sharedFolders),
		zap.Int("total_unique_folders", totalUniqueFolders),
		zap.Int("would_be_simple_sum", ownedFolders+sharedFolders))

	return response, nil
}
