// codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/internal/usecase/tag/delete.go
package tag

import (
	"context"
	"fmt"
	"time"

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

	dom_collection "codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/internal/domain/collection"
	dom_file "codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/internal/domain/file"
	dom_tag "codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/internal/domain/tag"
)

type DeleteTagUseCase struct {
	tagRepo        dom_tag.Repository
	collectionRepo dom_collection.CollectionRepository
	fileRepo       dom_file.FileMetadataRepository
	logger         *zap.Logger
}

func NewDeleteTagUseCase(
	tagRepo dom_tag.Repository,
	collectionRepo dom_collection.CollectionRepository,
	fileRepo dom_file.FileMetadataRepository,
	logger *zap.Logger,
) *DeleteTagUseCase {
	return &DeleteTagUseCase{
		tagRepo:        tagRepo,
		collectionRepo: collectionRepo,
		fileRepo:       fileRepo,
		logger:         logger.Named("DeleteTagUseCase"),
	}
}

func (uc *DeleteTagUseCase) Execute(ctx context.Context, userID, id gocql.UUID) error {
	// Remove tag from all collections and files before deleting
	// This runs synchronously to ensure data consistency
	uc.logger.Info("🏷️  TAG DELETE: Starting tag deletion",
		zap.String("tag_id", id.String()),
		zap.String("user_id", userID.String()))

	// Remove from all collections
	collections, err := uc.collectionRepo.ListByTagID(ctx, id)
	if err != nil {
		uc.logger.Error("🏷️  TAG DELETE: Failed to list collections by tag",
			zap.String("tag_id", id.String()),
			zap.Error(err))
	} else {
		uc.logger.Info("🏷️  TAG DELETE: Found collections to clean up",
			zap.String("tag_id", id.String()),
			zap.Int("count", len(collections)))

		for _, collection := range collections {
			// Remove the tag from the collection's Tags array
			newTags := make([]dom_tag.EmbeddedTag, 0, len(collection.Tags))
			for _, embeddedTag := range collection.Tags {
				if embeddedTag.ID != id {
					newTags = append(newTags, embeddedTag)
				}
			}

			if len(newTags) != len(collection.Tags) {
				collection.Tags = newTags
				collection.ModifiedAt = time.Now()
				if err := uc.collectionRepo.Update(ctx, collection); err != nil {
					uc.logger.Error("🏷️  TAG DELETE: Failed to update collection",
						zap.String("tag_id", id.String()),
						zap.String("collection_id", collection.ID.String()),
						zap.Error(err))
				} else {
					uc.logger.Debug("🏷️  TAG DELETE: Removed tag from collection",
						zap.String("tag_id", id.String()),
						zap.String("collection_id", collection.ID.String()))
				}
			}
		}
	}

	// Remove from all files
	files, err := uc.fileRepo.ListByTagID(ctx, id)
	if err != nil {
		uc.logger.Error("🏷️  TAG DELETE: Failed to list files by tag",
			zap.String("tag_id", id.String()),
			zap.Error(err))
	} else {
		uc.logger.Info("🏷️  TAG DELETE: Found files to clean up",
			zap.String("tag_id", id.String()),
			zap.Int("count", len(files)))

		for _, file := range files {
			// Remove the tag from the file's Tags array
			newTags := make([]dom_tag.EmbeddedTag, 0, len(file.Tags))
			for _, embeddedTag := range file.Tags {
				if embeddedTag.ID != id {
					newTags = append(newTags, embeddedTag)
				}
			}

			if len(newTags) != len(file.Tags) {
				file.Tags = newTags
				file.ModifiedAt = time.Now()
				if err := uc.fileRepo.Update(file); err != nil {
					uc.logger.Error("🏷️  TAG DELETE: Failed to update file",
						zap.String("tag_id", id.String()),
						zap.String("file_id", file.ID.String()),
						zap.Error(err))
				} else {
					uc.logger.Debug("🏷️  TAG DELETE: Removed tag from file",
						zap.String("tag_id", id.String()),
						zap.String("file_id", file.ID.String()))
				}
			}
		}
	}

	// Finally, delete the tag itself
	if err := uc.tagRepo.DeleteByID(ctx, userID, id); err != nil {
		return fmt.Errorf("failed to delete tag: %w", err)
	}

	uc.logger.Info("🏷️  TAG DELETE: Completed tag deletion",
		zap.String("tag_id", id.String()))

	return nil
}
