// monorepo/cloud/maplefile-backend/internal/maplefile/repo/collection/impl.go
package collection

import (
	"encoding/json"

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

	"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/config"
	"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/internal/domain/crypto"
	dom_collection "codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/internal/domain/collection"
	"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/internal/domain/tag"
)

type collectionRepositoryImpl struct {
	Logger  *zap.Logger
	Session *gocql.Session
}

func NewRepository(appCfg *config.Configuration, session *gocql.Session, loggerp *zap.Logger) dom_collection.CollectionRepository {
	loggerp = loggerp.Named("CollectionRepository")

	return &collectionRepositoryImpl{
		Logger:  loggerp,
		Session: session,
	}
}

// Helper functions for JSON serialization
func (impl *collectionRepositoryImpl) serializeAncestorIDs(ancestorIDs []gocql.UUID) (string, error) {
	if len(ancestorIDs) == 0 {
		return "[]", nil
	}
	data, err := json.Marshal(ancestorIDs)
	return string(data), err
}

func (impl *collectionRepositoryImpl) deserializeAncestorIDs(data string) ([]gocql.UUID, error) {
	if data == "" || data == "[]" {
		return []gocql.UUID{}, nil
	}
	var ancestorIDs []gocql.UUID
	err := json.Unmarshal([]byte(data), &ancestorIDs)
	return ancestorIDs, err
}

func (impl *collectionRepositoryImpl) serializeEncryptedCollectionKey(key *crypto.EncryptedCollectionKey) (string, error) {
	if key == nil {
		return "", nil
	}
	data, err := json.Marshal(key)
	return string(data), err
}

func (impl *collectionRepositoryImpl) deserializeEncryptedCollectionKey(data string) (*crypto.EncryptedCollectionKey, error) {
	if data == "" {
		return nil, nil
	}
	var key crypto.EncryptedCollectionKey
	err := json.Unmarshal([]byte(data), &key)
	return &key, err
}

func (impl *collectionRepositoryImpl) serializeTags(tags []tag.EmbeddedTag) (string, error) {
	if len(tags) == 0 {
		return "[]", nil
	}
	data, err := json.Marshal(tags)
	return string(data), err
}

func (impl *collectionRepositoryImpl) deserializeTags(data string) ([]tag.EmbeddedTag, error) {
	if data == "" || data == "[]" {
		return []tag.EmbeddedTag{}, nil
	}
	var tags []tag.EmbeddedTag
	err := json.Unmarshal([]byte(data), &tags)
	return tags, err
}

// isValidUUID checks if UUID is not nil/empty
func (impl *collectionRepositoryImpl) isValidUUID(id gocql.UUID) bool {
	return id.String() != "00000000-0000-0000-0000-000000000000"
}

// Permission helper method
func (impl *collectionRepositoryImpl) hasPermission(userPermission, requiredPermission string) bool {
	permissionLevels := map[string]int{
		dom_collection.CollectionPermissionReadOnly:  1,
		dom_collection.CollectionPermissionReadWrite: 2,
		dom_collection.CollectionPermissionAdmin:     3,
	}

	userLevel, userExists := permissionLevels[userPermission]
	requiredLevel, requiredExists := permissionLevels[requiredPermission]

	if !userExists || !requiredExists {
		return false
	}

	return userLevel >= requiredLevel
}

// Helper to generate null UUID for root collections
func (impl *collectionRepositoryImpl) nullParentUUID() gocql.UUID {
	return gocql.UUID{} // All zeros represents null parent
}

// Helper to build ancestor depth entries for hierarchy table
func (impl *collectionRepositoryImpl) buildAncestorDepthEntries(collectionID gocql.UUID, ancestorIDs []gocql.UUID) []ancestorDepthEntry {
	var entries []ancestorDepthEntry

	for i, ancestorID := range ancestorIDs {
		depth := i + 1 // Depth starts at 1 for direct parent
		entries = append(entries, ancestorDepthEntry{
			AncestorID:   ancestorID,
			Depth:        depth,
			CollectionID: collectionID,
		})
	}

	return entries
}

type ancestorDepthEntry struct {
	AncestorID   gocql.UUID
	Depth        int
	CollectionID gocql.UUID
}
