package cluster

import (
	"context"
	"fmt"

	"github.com/mitchellh/mapstructure"
	"sigs.k8s.io/controller-runtime/pkg/client"
	"sigs.k8s.io/controller-runtime/pkg/log"

	"github.com/tidbcloud/eks-provider/controllers/workflow/action"
	cloudv1 "github.com/tidbcloud/infra-api/api/v1"
	"github.com/tidbcloud/infra-provider/pkg/consts"
)

// toggleLBTargetAction toggles the LB target between TiProxy and TiDB
type toggleLBTargetAction struct {
	cli client.Client
}

type toggleLBTargetInputs struct {
	Namespace  string `mapstructure:"namespace" json:"namespace" validate:"required"`
	Name       string `mapstructure:"name" json:"name" validate:"required"`
	GroupID    string `mapstructure:"groupId" json:"groupId" validate:"required"`
	UseTiProxy bool   `mapstructure:"useTiProxy" json:"useTiProxy" validate:"omitempty"`
}

var (
	_ action.Action = &toggleLBTargetAction{}
)

func NewToggleLBTargetAction(cli client.Client) action.Action {
	return &toggleLBTargetAction{cli: cli}
}

func (a *toggleLBTargetAction) Name() cloudv1.WorkflowActionName {
	return consts.WorkflowActionToggleLBTarget
}

func (a *toggleLBTargetAction) PreCheck(ctx context.Context, wf *cloudv1.Workflow, step cloudv1.WorkflowStep) error {
	inputs := &toggleLBTargetInputs{}
	if err := mapstructure.Decode(step.Inputs.Object, inputs); err != nil {
		return fmt.Errorf("decode inputs: %w", err)
	}
	if err := validate.Struct(inputs); err != nil {
		return fmt.Errorf("validate inputs: %w", err)
	}
	return nil
}

func (a *toggleLBTargetAction) Handle(ctx context.Context, wf *cloudv1.Workflow, step cloudv1.WorkflowStep) error {
	logger := log.FromContext(ctx)

	inputs := &toggleLBTargetInputs{}
	_ = mapstructure.Decode(step.Inputs.Object, inputs)

	cluster, err := getCluster(ctx, a.cli, client.ObjectKey{Namespace: inputs.Namespace, Name: inputs.Name})
	if err != nil {
		return err
	}

	sqlEndpoints, found := cluster.GetSQLEndpoints(inputs.GroupID)
	if !found {
		return cloudv1.NewWFNonRetriableError(fmt.Errorf("group %s not found", inputs.GroupID))
	}

	logger.Info("toggle LB target", "groupID", inputs.GroupID, "useTiProxy", inputs.UseTiProxy)
	sqlEndpoints.UseTiProxyAsLBTarget = inputs.UseTiProxy
	if err := a.cli.Update(ctx, cluster); err != nil {
		return fmt.Errorf("update cluster: %w", err)
	}

	return nil
}
