package page

import (
	"context"
	"fmt"

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

	pageusecase "codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/internal/usecase/page"
)

// DeletePagesService handles page deletion operations
type DeletePagesService interface {
	DeletePages(ctx context.Context, tenantID, siteID gocql.UUID, input *pageusecase.DeletePagesInput) (*pageusecase.DeletePagesOutput, error)
	DeleteAllPages(ctx context.Context, tenantID, siteID gocql.UUID) (*pageusecase.DeletePagesOutput, error)
}

type deletePagesService struct {
	// Focused usecases
	validateSiteUC      *pageusecase.ValidateSiteForDeletionUseCase
	deletePagesRepoUC   *pageusecase.DeletePagesFromRepoUseCase
	deletePagesSearchUC *pageusecase.DeletePagesFromSearchUseCase

	logger *zap.Logger
}

// NewDeletePagesService creates a new DeletePagesService
func NewDeletePagesService(
	validateSiteUC *pageusecase.ValidateSiteForDeletionUseCase,
	deletePagesRepoUC *pageusecase.DeletePagesFromRepoUseCase,
	deletePagesSearchUC *pageusecase.DeletePagesFromSearchUseCase,
	logger *zap.Logger,
) DeletePagesService {
	return &deletePagesService{
		validateSiteUC:      validateSiteUC,
		deletePagesRepoUC:   deletePagesRepoUC,
		deletePagesSearchUC: deletePagesSearchUC,
		logger:              logger.Named("delete-pages-service"),
	}
}

// DeletePages orchestrates the deletion of specific pages
func (s *deletePagesService) DeletePages(ctx context.Context, tenantID, siteID gocql.UUID, input *pageusecase.DeletePagesInput) (*pageusecase.DeletePagesOutput, error) {
	s.logger.Info("deleting pages",
		zap.String("tenant_id", tenantID.String()),
		zap.String("site_id", siteID.String()),
		zap.Int("page_count", len(input.PageIDs)))

	// Step 1: Validate site
	_, err := s.validateSiteUC.Execute(ctx, tenantID, siteID)
	if err != nil {
		s.logger.Error("failed to validate site", zap.Error(err))
		return nil, err
	}

	// Step 2: Delete pages from database
	deleteResult, err := s.deletePagesRepoUC.Execute(ctx, siteID, input.PageIDs)
	if err != nil {
		s.logger.Error("failed to delete pages from database", zap.Error(err))
		return nil, err
	}

	// Step 3: Delete pages from search index (only if database delete succeeded)
	deindexedCount := 0
	if deleteResult.DeletedCount > 0 {
		// Only delete pages that were successfully deleted from database
		successfulPageIDs := s.getSuccessfulPageIDs(input.PageIDs, deleteResult.FailedPages)
		if len(successfulPageIDs) > 0 {
			deindexedCount, _ = s.deletePagesSearchUC.Execute(ctx, siteID, successfulPageIDs)
		}
	}

	// Step 4: Build output
	message := fmt.Sprintf("Successfully deleted %d pages from database, removed %d from search index",
		deleteResult.DeletedCount, deindexedCount)
	if len(deleteResult.FailedPages) > 0 {
		message += fmt.Sprintf(", failed %d pages", len(deleteResult.FailedPages))
	}

	s.logger.Info("pages deleted successfully",
		zap.String("site_id", siteID.String()),
		zap.Int("deleted", deleteResult.DeletedCount),
		zap.Int("deindexed", deindexedCount),
		zap.Int("failed", len(deleteResult.FailedPages)))

	return &pageusecase.DeletePagesOutput{
		DeletedCount:   deleteResult.DeletedCount,
		DeindexedCount: deindexedCount,
		FailedPages:    deleteResult.FailedPages,
		Message:        message,
	}, nil
}

// DeleteAllPages orchestrates the deletion of all pages for a site
func (s *deletePagesService) DeleteAllPages(ctx context.Context, tenantID, siteID gocql.UUID) (*pageusecase.DeletePagesOutput, error) {
	s.logger.Info("deleting all pages",
		zap.String("tenant_id", tenantID.String()),
		zap.String("site_id", siteID.String()))

	// Step 1: Validate site
	_, err := s.validateSiteUC.Execute(ctx, tenantID, siteID)
	if err != nil {
		s.logger.Error("failed to validate site", zap.Error(err))
		return nil, err
	}

	// Step 2: Delete all pages from database
	count, err := s.deletePagesRepoUC.ExecuteDeleteAll(ctx, siteID)
	if err != nil {
		s.logger.Error("failed to delete all pages from database", zap.Error(err))
		return nil, err
	}

	// Step 3: Delete all documents from search index
	_ = s.deletePagesSearchUC.ExecuteDeleteAll(ctx, siteID)

	s.logger.Info("all pages deleted successfully",
		zap.String("site_id", siteID.String()),
		zap.Int64("count", count))

	return &pageusecase.DeletePagesOutput{
		DeletedCount:   int(count),
		DeindexedCount: int(count),
		Message:        fmt.Sprintf("Successfully deleted all %d pages", count),
	}, nil
}

// Helper: Get list of page IDs that were successfully deleted (exclude failed ones)
func (s *deletePagesService) getSuccessfulPageIDs(allPageIDs, failedPageIDs []string) []string {
	if len(failedPageIDs) == 0 {
		return allPageIDs
	}

	failedMap := make(map[string]bool, len(failedPageIDs))
	for _, id := range failedPageIDs {
		failedMap[id] = true
	}

	successful := make([]string, 0, len(allPageIDs)-len(failedPageIDs))
	for _, id := range allPageIDs {
		if !failedMap[id] {
			successful = append(successful, id)
		}
	}

	return successful
}
