package create

import (
	"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/dataplane"
	"github.com/tidbcloud/metrics-integration/global/internal/infrastructure/di"
	"github.com/tidbcloud/metrics-integration/global/internal/infrastructure/helm"
	"github.com/tidbcloud/metrics-integration/global/internal/infrastructure/workflow"
	helmpackage "github.com/tidbcloud/metrics-integration/global/pkg/helm/pipeline"
	"github.com/tidbcloud/pkgv2/secret/encrypt"

	"github.com/shiningrush/fastflow/pkg/entity/run"
	"gorm.io/gorm"
)

type PipelineCreateAction struct{}

func (a *PipelineCreateAction) Name() string {
	return "PipelineCreateAction"
}

func (a *PipelineCreateAction) Run(ctx run.ExecuteContext, params interface{}) error {
	id, err := workflow.GetUint64FromRunVar(ctx, "id")
	if err != nil {
		return fmt.Errorf("invalid id: %v", err)
	}

	pipelineMetaData := &entity.Integration{}
	if err := di.DiCall(func(db *gorm.DB) error {
		return db.First(pipelineMetaData, id).Error
	}); err != nil {
		return fmt.Errorf("failed to get pipeline from db: %w", err)
	}

	// helm deploy

	// get targetCluster
	targetCluster, err := helmpackage.GetTargetClusterByClusterID(uint64(pipelineMetaData.ClusterID))
	if err != nil {
		return fmt.Errorf("failed to get clusterinfo: %w", err)
	}

	// get decrypted API key
	decryptedAPIKey := ""
	if err := di.DiCall(func(encryptor encrypt.Encryptor) error {
		switch pipelineMetaData.ProviderType {
		case entity.IntegrationTypeDatadog:
			if len(pipelineMetaData.EncryptedDatadogApiKey) > 0 {
				secret, err := encrypt.DecryptBase64(encryptor, pipelineMetaData.EncryptedDatadogApiKey)
				if err != nil {
					return fmt.Errorf("%s, please check the key or region", err.Error())
				}
				decryptedAPIKey = secret.String()
				return nil
			}
		case entity.IntegrationTypeNewrelic:
			if len(pipelineMetaData.EncryptedNewrelicApiKey) > 0 {
				secret, err := encrypt.DecryptBase64(encryptor, pipelineMetaData.EncryptedNewrelicApiKey)
				if err != nil {
					return fmt.Errorf("%s, please check the key or region", err.Error())
				}
				decryptedAPIKey = secret.String()
				return nil
			}
		}
		return nil
	}); err != nil {
		return fmt.Errorf("failed to decrypt api key: %v", err)
	}

	excludeImageUpdate := false
	packageConfig := helmpackage.NewPipelineConfig(fmt.Sprintf("%d", id), targetCluster, pipelineMetaData, decryptedAPIKey, excludeImageUpdate)

	serverAddr := config.Global().RegionalExecutorConfig.GetPipelineDataplaneServerAddr(id, string(pipelineMetaData.CloudProviderType), pipelineMetaData.Region)
	if serverAddr != "" {
		if err := helm.RemoteApply(ctx.Context(), packageConfig, serverAddr); err != nil {
			return fmt.Errorf("failed to apply helm chart: %w", err)
		}
	} else {
		// if serverAddr is nil, fall back to global dataplane
		// get dataplane rest config
		restConfig, err := dataplane.GetRestConfig(pipelineMetaData.Region)
		if err != nil {
			return fmt.Errorf("failed to get rest config: %w", err)
		}

		if err := helm.Apply(ctx.Context(), restConfig, packageConfig); err != nil {
			return err
		}
	}

	// update metadb
	if err := di.DiCall(func(db *gorm.DB) error {
		p := &entity.Integration{
			Updatable: entity.Updatable{
				Base: entity.Base{
					ID: entity.ID(id),
				},
			},
			Status: entity.IntegrationStatusActive,
		}

		db.Model(p).Updates(p)
		return nil
	}); err != nil {
		return fmt.Errorf("write metadb failed: %s", err)
	}

	return nil
}
