package action

import (
	"fmt"

	dplanemgrv1 "github.com/tidbcloud/cluster-service-ng/api/dataplane-manager/v1"
	"github.com/tidbcloud/cluster-service-ng/domain/entity"
	"github.com/tidbcloud/cluster-service-ng/domain/workflow"
	"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 DeleteLoadBalanceAction struct {
	sharedPoolRepo repo.SharedPoolRepo
	tidbGroupRepo  repo.TiDBGroupRepo
	client         dplanemgrv1.LoadBalancerServiceClient
}

const DeleteLoadBalanceActionName = "delete-load-balance"

func (a *DeleteLoadBalanceAction) Name() string {
	return DeleteLoadBalanceActionName
}

func NewDeleteLoadBalanceAction(
	sharedPoolRepo repo.SharedPoolRepo,
	tidbGroupRepo repo.TiDBGroupRepo,
	client dplanemgrv1.LoadBalancerServiceClient,
) actions.Action {
	return &DeleteLoadBalanceAction{
		sharedPoolRepo: sharedPoolRepo,
		tidbGroupRepo:  tidbGroupRepo,
		client:         client,
	}
}

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

	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)
	}

	tidbGroupId, err := args.GetString(workflow.TiDBGroupIdKey)
	if err != nil {
		tilog.Error(ctx, "failed to get tidb group id", zap.Error(err))
		return fmt.Errorf("failed to get tidb group id: %w", err)
	}

	// load tidb group
	tidbGroup, err := a.tidbGroupRepo.Load(ctx, tidbGroupId, true)
	if err != nil {
		tilog.Error(ctx, "failed to load tidb group", zap.Error(err))
		return fmt.Errorf("failed to load tidb group: %w", err)
	}

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

	tidbGroup.SqlEndpoint = &entity.SQLEndpoint{
		PrivateLb: &entity.LoadBalancer{
			Enabled: false,
		},
		PublicLb: &entity.LoadBalancer{
			Enabled: false,
		},
	}

	// public load balancer
	_, err = a.client.DeleteLoadBalancer(ctx, &dplanemgrv1.DeleteLoadBalancerRequest{
		DataPlaneId: tidbGroup.GetDataplaneName(),
		Id:          entity.GetPublicSvcName(tidbGroup.GetId()),
	})
	if err != nil {
		tilog.Error(ctx, "failed to delete public load balancer",
			zap.String("tidbGroupId", tidbGroup.GetId()),
			zap.Error(err),
		)
		return fmt.Errorf("failed to delete public load balancer: %w", err)
	}

	// private lb
	_, err = a.client.DeleteLoadBalancer(ctx, &dplanemgrv1.DeleteLoadBalancerRequest{
		DataPlaneId: tidbGroup.GetDataplaneName(),
		Id:          entity.GetPrivateSvcName(tidbGroup.GetId()),
	})
	if err != nil {
		tilog.Error(ctx, "failed to delete private load balancer",
			zap.String("tidbGroupId", tidbGroup.GetId()),
			zap.Error(err),
		)
		return fmt.Errorf("failed to delete private load balancer: %w", err)
	}

	tilog.Info(ctx, "successfully delete all load balancer for tidb group",
		zap.String("tidbGroupId", tidbGroup.GetId()),
		zap.String("sharedPoolId", sharedPool.GetId()))

	return nil
}
