package action

import (
	"fmt"

	"github.com/pingcap/kvproto/pkg/keyspacepb"
	"github.com/tidbcloud/cluster-service-ng/domain/workflow"
	"github.com/tidbcloud/cluster-service-ng/pkg/clustergateway"
	"github.com/tidbcloud/cluster-service-ng/pkg/runtime/actions"
	"github.com/tidbcloud/cluster-service-ng/pkg/storage/repo"
	"github.com/tidbcloud/cluster-service-ng/pkg/utils"
	"github.com/tidbcloud/tiinf/monitor/tilog"
	"go.uber.org/zap"
)

type DeleteKeySpaceAction struct {
	sharedPoolRepo    repo.SharedPoolRepo
	tidbClusterRepo   repo.TiDBClusterRepo
	clusterGatewayCli clustergateway.Client
}

const DeleteKeySpaceActionName = "delete-keyspace"

func NewDeleteKeySpaceAction(
	sharedPoolRepo repo.SharedPoolRepo,
	tidbClusterRepo repo.TiDBClusterRepo,
	clusterGatewayCli clustergateway.Client,
) actions.Action {
	return &DeleteKeySpaceAction{
		sharedPoolRepo:    sharedPoolRepo,
		tidbClusterRepo:   tidbClusterRepo,
		clusterGatewayCli: clusterGatewayCli,
	}
}

func (a *DeleteKeySpaceAction) Name() string {
	return DeleteKeySpaceActionName
}

func (a *DeleteKeySpaceAction) Invoke(args actions.ActionArgs) error {
	// generate context
	ctx := utils.GenerateContext(args)
	tilog.Info(ctx, "delete keyspace action invoked")

	// get sharedPool id
	sharedPoolId, err := args.GetString(workflow.SharedPoolIdKey)
	if err != nil {
		tilog.Error(ctx, "failed to get sharedPool id", zap.Error(err))
		return fmt.Errorf("failed to get sharedPool id: %w", err)
	}

	// load sharedPool
	sharedPool, err := a.sharedPoolRepo.Load(ctx, sharedPoolId, false)
	if err != nil {
		tilog.Error(ctx, "failed to load sharedPool", zap.String("sharedPoolId", sharedPoolId), zap.Error(err))
		return fmt.Errorf("failed to load sharedPool: %w", err)
	}

	tidbClusterId, err := args.GetString(workflow.TiDBClusterIdKey)
	if err != nil {
		tilog.Error(ctx, "failed to get tidb cluster id", zap.Error(err))
		return fmt.Errorf("failed to get tidb cluster id: %w", err)
	}
	// load tidb cluster
	tidbCluster, err := a.tidbClusterRepo.Load(ctx, tidbClusterId, true)
	if err != nil {
		tilog.Error(ctx, "failed to load tidb cluster", zap.String("tidbClusterId", tidbClusterId), zap.Error(err))
		return fmt.Errorf("failed to load tidb cluster: %w", err)
	}

	// get keyspace
	keyspaceMeta, err := a.clusterGatewayCli.GetKeySpace(ctx, sharedPool, tidbCluster.GetId())
	if err != nil {
		if clustergateway.IsNotFoundError(err) {
			tilog.Warn(ctx, "keyspace not found, no need to delete", zap.String("keyspace", tidbCluster.GetId()))
			return nil
		}

		tilog.Error(ctx, "failed to get keyspace", zap.String("keyspace", tidbCluster.GetId()), zap.Error(err))
		return fmt.Errorf("failed to get keyspace: %w", err)
	}

	switch keyspaceMeta.State {
	case keyspacepb.KeyspaceState_ENABLED:
		// update keyspace state to disabled
		err = a.clusterGatewayCli.UpdateKeySpaceState(ctx, sharedPool, tidbCluster.GetId(), keyspacepb.KeyspaceState_DISABLED)
		if err != nil {
			tilog.Error(ctx, "failed to update keyspace state to disabled", zap.String("keyspace", tidbCluster.GetId()), zap.Error(err))
			return fmt.Errorf("failed to update keyspace state to disabled: %w", err)
		}
		return fmt.Errorf("keyspace %s is not disabled, please try again later", tidbCluster.GetId())
	case keyspacepb.KeyspaceState_DISABLED:
		// update keyspace state to archived
		err = a.clusterGatewayCli.UpdateKeySpaceState(ctx, sharedPool, tidbCluster.GetId(), keyspacepb.KeyspaceState_ARCHIVED)
		if err != nil {
			tilog.Error(ctx, "failed to update keyspace state to archived", zap.String("keyspace", tidbCluster.GetId()), zap.Error(err))
			return fmt.Errorf("failed to update keyspace state to archived: %w", err)
		}
		return fmt.Errorf("keyspace %s is not archived, please try again later", tidbCluster.GetId())
	case keyspacepb.KeyspaceState_ARCHIVED:
		tilog.Warn(ctx, "keyspace is already archived", zap.String("keyspace", tidbCluster.GetId()))
		return nil
	}

	tilog.Info(ctx, "delete keyspace successfully", zap.String("keyspace", tidbCluster.GetId()), zap.String("sharedPoolId", sharedPoolId))

	return nil
}
