package prometheus

import (
	"context"
	"fmt"

	"github.com/tidbcloud/metrics-integration/global/internal/domain/entity"
	"github.com/tidbcloud/metrics-integration/global/internal/infrastructure/config"
	"github.com/tidbcloud/metrics-integration/global/internal/infrastructure/di"
	"github.com/tidbcloud/metrics-integration/global/internal/infrastructure/promconfig"
	"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 PrometheusWithClusterDeleting struct{}

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

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

func (r *PrometheusWithClusterDeleting) Execute(
	ctx context.Context, event *clusterevent.ClusterEvent, cluster *mgmt.Cluster,
) error {
	logger := log.GetLogger(ctx).Named("PrometheusWithClusterDeleting")
	// 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("metricskey event: CleanUnusedmetricskeyClusterJob",
		zap.Uint64("clusterID", cluster.ClusterId))

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

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

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

	// Delete each metricskey
	for _, metricskey := range metricsKeys {
		if err := r.deleteMetricsKey(metricskey, logger); err != nil {
			logger.Error("failed to delete metricskey",
				zap.Uint64("keyId", uint64(metricskey.ID)),
				zap.Uint64("clusterID", cluster.ClusterId),
				zap.Error(err))
			// Continue with other metricskeys even if one fails
			continue
		}

		logger.Info("successfully deleted metricskey",
			zap.Uint64("keyId", uint64(metricskey.ID)),
			zap.Uint64("clusterID", cluster.ClusterId))
	}

	return nil
}

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

	// delete pipeline resources
	if err := promconfig.RemoteDeleteMetricsKey(context.Background(), fmt.Sprintf("%d", metricskey.ClusterID), metricskey.KeyHash, config.Global().RegionalExecutorConfig.GetServerAddr(string(metricskey.CloudProviderType), metricskey.Region)); err != nil {
		return fmt.Errorf("failed to remote delete metrics key to cluster: %v", err)
	}

	return di.DiCall(func(db *gorm.DB) error {
		if err := db.Transaction(func(tx *gorm.DB) error {
			// delete metrics key by primary key (safer and uses model type)
			if err := tx.Delete(&entity.MetricsKey{}, metricskey.ID).Error; err != nil {
				return fmt.Errorf("failed to delete metrics key: %w", err)
			}

			// delete associated general integration for this metrics key and provider
			if err := tx.Where("id = ? AND provider_type = ?", metricskey.ID, entity.IntegrationTypePrometheus).
				Delete(&entity.GeneralIntegration{}).Error; err != nil {
				return fmt.Errorf("failed to delete general integration for metrics key: %w", err)
			}

			return nil
		}); err != nil {
			return err
		}

		return nil
	})
}
