package integration

import (
	"context"
	"fmt"

	"github.com/shiningrush/fastflow/pkg/mod"
	"github.com/tidbcloud/metrics-integration/global/internal/domain/entity"
	"github.com/tidbcloud/metrics-integration/global/internal/infrastructure/di"
	"github.com/tidbcloud/metrics-integration/global/pkg/log"
	mgmt "github.com/tidbcloud/tidb-management-service/api/spec/tidb_mgmt_service/v1"
	clusterevent "github.com/tidbcloud/tidb-management-service/utilities/clusterevent"
	"go.uber.org/zap"
	"gorm.io/gorm"
)

type IntegrationWithClusterDeleting struct{}

func (r *IntegrationWithClusterDeleting) Name() string {
	return "IntegrationWithClusterDeleting"
}

func (r *IntegrationWithClusterDeleting) Match(event *clusterevent.ClusterEvent) bool {
	return event.EventType == clusterevent.EventTypeDeleting
}

func (r *IntegrationWithClusterDeleting) Execute(
	ctx context.Context, event *clusterevent.ClusterEvent, cluster *mgmt.Cluster,
) error {
	logger := log.GetLogger(ctx).Named("IntegrationWithClusterDeleting")
	// Additional validation: ensure cluster information is provided and valid
	if cluster == nil || cluster.ClusterId == 0 {
		logger.Error("cluster information is nil, cannot proceed with deletion")
		return fmt.Errorf("cluster information is required but not provided")
	}
	logger.Info("integration event: CleanUnusedIntegrationClusterJob",
		zap.Uint64("clusterID", cluster.ClusterId))

	// Get all integrations by cluster ID
	var integrations []entity.Integration
	if err := di.DiCall(func(db *gorm.DB) error {
		return db.Model(&entity.Integration{}).
			Where("cluster_id = ? AND status != ?", cluster.ClusterId, entity.IntegrationStatusNone).
			Find(&integrations).Error
	}); err != nil {
		logger.Error("failed to query integrations by cluster ID",
			zap.Uint64("clusterID", cluster.ClusterId),
			zap.Error(err))
		return fmt.Errorf("query integrations failed: %w", err)
	}

	// If no integrations found, no cleanup needed
	if len(integrations) == 0 {
		logger.Info("no active integrations found for cluster",
			zap.Uint64("clusterID", cluster.ClusterId))
		return nil
	}

	logger.Info("found integrations to delete",
		zap.Uint64("clusterID", cluster.ClusterId),
		zap.Int("count", len(integrations)))

	// Delete each integration
	for _, integration := range integrations {
		if err := r.deleteIntegration(integration, logger); err != nil {
			logger.Error("failed to delete integration",
				zap.Uint64("integrationID", uint64(integration.ID)),
				zap.Uint64("clusterID", cluster.ClusterId),
				zap.String("providerType", string(integration.ProviderType)),
				zap.Error(err))
			// Continue with other integrations even if one fails
			continue
		}

		logger.Info("successfully deleted integration",
			zap.Uint64("integrationID", uint64(integration.ID)),
			zap.Uint64("clusterID", cluster.ClusterId),
			zap.String("providerType", string(integration.ProviderType)))
	}

	return nil
}

// deleteIntegration performs the deletion of a single integration
func (r *IntegrationWithClusterDeleting) deleteIntegration(integration entity.Integration, logger *zap.Logger) error {
	// Validate integration ID to prevent unauthorized operations
	if integration.ID == 0 {
		logger.Error("integration ID is empty or zero, skipping deletion to prevent unauthorized access",
			zap.Uint64("integrationID", uint64(integration.ID)))
		return fmt.Errorf("invalid integration ID: cannot be empty or zero")
	}

	return di.DiCall(func(db *gorm.DB) error {
		// Update status to NONE to mark as deleted
		if err := db.Model(&entity.Integration{}).
			Where("id = ?", integration.ID).
			Update("status", entity.IntegrationStatusNone).Error; err != nil {
			return fmt.Errorf("failed to update integration status: %w", err)
		}

		// Run workflow to delete pipeline resources
		if _, err := mod.GetCommander().RunDagWithTags("delete-pipeline", map[string]string{
			"id": fmt.Sprintf("%d", integration.ID),
		}, map[string]string{}); err != nil {
			logger.Warn("failed to run delete-pipeline workflow, but integration status updated",
				zap.Uint64("integrationID", uint64(integration.ID)),
				zap.Error(err))
			// Don't return error here as the status is already updated
			// The workflow failure is logged but won't block the deletion
		}

		return nil
	})
}
