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

import (
	"time"

	"github.com/gocql/gocql"
	"go.uber.org/zap"

	dom_collection "codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/internal/domain/collection"
	"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/pkg/validation"
)

// Helper function to get owner email from members list
// The owner is always a member with their email, so we can look them up
func getOwnerEmailFromMembers(collection *dom_collection.Collection) string {
	if collection == nil {
		return ""
	}
	for _, member := range collection.Members {
		if member.RecipientID == collection.OwnerID {
			return member.RecipientEmail
		}
	}
	return ""
}

// Helper function to map a CollectionMembershipDTO to a CollectionMembership domain model
// This assumes a direct field-by-field copy is intended by the DTO structure.
func mapMembershipDTOToDomain(dto *CollectionMembershipDTO) dom_collection.CollectionMembership {
	return dom_collection.CollectionMembership{
		ID:                     dto.ID,                     // Copy DTO ID
		CollectionID:           dto.CollectionID,           // Copy DTO CollectionID
		RecipientID:            dto.RecipientID,            // Copy DTO RecipientID
		RecipientEmail:         dto.RecipientEmail,         // Copy DTO RecipientEmail
		GrantedByID:            dto.GrantedByID,            // Copy DTO GrantedByID
		EncryptedCollectionKey: dto.EncryptedCollectionKey, // Copy DTO EncryptedCollectionKey
		PermissionLevel:        dto.PermissionLevel,        // Copy DTO PermissionLevel
		CreatedAt:              dto.CreatedAt,              // Copy DTO CreatedAt
		IsInherited:            dto.IsInherited,            // Copy DTO IsInherited
		InheritedFromID:        dto.InheritedFromID,        // Copy DTO InheritedFromID
		// Note: ModifiedAt/By, Version are not in Membership DTO/Domain
	}
}

// Helper function to map a CreateCollectionRequestDTO to a Collection domain model.
// This function recursively maps all fields, including nested members and children,
// copying values directly from the DTO. Server-side overrides for fields like
// ID, OwnerID, timestamps, and version are applied *after* this mapping in the Execute method.
// userID and now are passed for potential use in recursive calls if needed for consistency,
// though the primary goal here is to copy DTO values.
func mapCollectionDTOToDomain(dto *CreateCollectionRequestDTO, userID gocql.UUID, now time.Time) *dom_collection.Collection {
	if dto == nil {
		return nil
	}

	collection := &dom_collection.Collection{
		// Copy all scalar/pointer fields directly from the DTO as requested by the prompt.
		// Fields like ID, OwnerID, timestamps, and version from the DTO
		// represent the client's proposed state and will be potentially
		// overridden by server-managed values later in the Execute method.
		ID:                     dto.ID,
		OwnerID:                dto.OwnerID,
		EncryptedName:          dto.EncryptedName,
		EncryptedCustomIcon:    dto.EncryptedCustomIcon,
		CollectionType:         dto.CollectionType,
		EncryptedCollectionKey: dto.EncryptedCollectionKey,
		ParentID:               dto.ParentID,
		AncestorIDs:            dto.AncestorIDs,
		CreatedAt:              dto.CreatedAt,
		CreatedByUserID:        dto.CreatedByUserID,
		ModifiedAt:             dto.ModifiedAt,
		ModifiedByUserID:       dto.ModifiedByUserID,
	}

	// Map members slice from DTO to domain model slice
	if len(dto.Members) > 0 {
		collection.Members = make([]dom_collection.CollectionMembership, len(dto.Members))
		for i, memberDTO := range dto.Members {
			collection.Members[i] = mapMembershipDTOToDomain(memberDTO)
		}
	}

	return collection
}

// Helper function to map a Collection domain model to a CollectionResponseDTO
// This function should ideally exclude sensitive data (like recipient-specific keys)
// that should not be part of a general response.
// fileCount is the number of active files in this collection (pass 0 if not known)
// ownerEmail is the email address of the collection owner (pass "" if not known)
func mapCollectionToDTO(collection *dom_collection.Collection, fileCount int, ownerEmail string) *CollectionResponseDTO {
	if collection == nil {
		return nil
	}

	responseDTO := &CollectionResponseDTO{
		ID:                  collection.ID,
		OwnerID:             collection.OwnerID,
		OwnerEmail:          ownerEmail,
		EncryptedName:       collection.EncryptedName,
		EncryptedCustomIcon: collection.EncryptedCustomIcon,
		CollectionType:      collection.CollectionType,
		ParentID:            collection.ParentID,
		AncestorIDs:         collection.AncestorIDs,
		Tags:                collection.Tags,
		// Note: EncryptedCollectionKey from the domain model is the owner's key.
		// Including it in the general response DTO might be acceptable if the response
		// is only sent to the owner and contains *their* key. Otherwise, this field
		// might need conditional inclusion or exclusion. The prompt does not require
		// changing this, so we keep the original mapping which copies the owner's key.
		EncryptedCollectionKey: collection.EncryptedCollectionKey,
		CreatedAt:              collection.CreatedAt,
		ModifiedAt:             collection.ModifiedAt,
		FileCount:              fileCount,
		Version:                collection.Version,
		// Members slice needs mapping to MembershipResponseDTO
		Members: make([]MembershipResponseDTO, len(collection.Members)),
	}

	// Map members
	for i, member := range collection.Members {
		responseDTO.Members[i] = MembershipResponseDTO{
			ID:              member.ID,
			RecipientID:     member.RecipientID,
			RecipientEmail:  member.RecipientEmail, // Email for display
			PermissionLevel: member.PermissionLevel,
			GrantedByID:     member.GrantedByID,
			CollectionID:    member.CollectionID, // Redundant but useful
			IsInherited:     member.IsInherited,
			InheritedFromID: member.InheritedFromID,
			CreatedAt:       member.CreatedAt,
			// Note: EncryptedCollectionKey for this member is recipient-specific
			// and should NOT be included in a general response DTO unless
			// filtered for the specific recipient receiving the response.
			// The MembershipResponseDTO does not have a field for this, which is correct.
			EncryptedCollectionKey: member.EncryptedCollectionKey,
		}
	}

	// Debug: Log what we're sending in the DTO
	logger, _ := zap.NewDevelopment()
	logger.Info("🔍 mapCollectionToDTO: Mapping collection to DTO",
		zap.String("collection_id", collection.ID.String()),
		zap.Int("domain_members_count", len(collection.Members)),
		zap.Int("dto_members_count", len(responseDTO.Members)),
		zap.Int("domain_tags_count", len(collection.Tags)),
		zap.Int("dto_tags_count", len(responseDTO.Tags)))
	for i, member := range responseDTO.Members {
		logger.Info("🔍 mapCollectionToDTO: DTO member",
			zap.Int("index", i),
			zap.String("recipient_email", validation.MaskEmail(member.RecipientEmail)),
			zap.String("recipient_id", member.RecipientID.String()),
			zap.Int("encrypted_key_length", len(member.EncryptedCollectionKey)))
	}

	return responseDTO
}
