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/internal/infrastructure/grpc/grpcli"
	"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 IntegrationWithClusterScaling struct{}

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

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

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

	if grpcli.GetClusterServicePlan(cluster) != "Dedicated" {
		logger.Info("skip pipeline runtime config refresh for non-dedicated cluster",
			zap.Uint64("clusterID", cluster.ClusterId),
			zap.String("servicePlan", grpcli.GetClusterServicePlan(cluster)))
		return nil
	}

	// Get all active 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.IntegrationStatusActive).
			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 active integrations found, no upgrade 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 upgrade",
		zap.Uint64("clusterID", cluster.ClusterId),
		zap.Int("count", len(integrations)))

	// Upgrade each integration using workflow
	for _, integration := range integrations {
		if err := r.upgradeIntegration(integration, logger); err != nil {
			logger.Error("failed to upgrade 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 triggered upgrade workflow for integration",
			zap.Uint64("integrationID", uint64(integration.ID)),
			zap.Uint64("clusterID", cluster.ClusterId),
			zap.String("providerType", string(integration.ProviderType)))
	}

	return nil
}

// upgradeIntegration triggers the workflow to upgrade a single integration
func (r *IntegrationWithClusterScaling) upgradeIntegration(
	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 upgrade to prevent unauthorized access",
			zap.Uint64("integrationID", uint64(integration.ID)))
		return fmt.Errorf("invalid integration ID: cannot be empty or zero")
	}

	// Refresh pipeline runtime config only. Do not use Helm apply for scale.
	if _, err := mod.GetCommander().RunDagWithTags("refresh-pipeline-runtime-config", map[string]string{
		"id": fmt.Sprintf("%d", integration.ID),
	}, map[string]string{}); err != nil {
		return fmt.Errorf("failed to run refresh-pipeline-runtime-config workflow: %w", err)
	}

	logger.Debug("refresh-pipeline-runtime-config workflow triggered successfully",
		zap.Uint64("integrationID", uint64(integration.ID)),
		zap.String("region", integration.Region))

	return nil
}
