package action

import (
	"strconv"

	"github.com/tidbcloud/fastflow/pkg/entity/run"
	regionaldedicatedv1 "github.com/tidbcloud/infra-provider/api/tidbcloud/regional-server/v1"
	"github.com/tidbcloud/tiinf/monitor/tilog"
	"go.uber.org/zap"

	"github.com/tidbcloud/tidb-management-service/dedicated-global-service/domain/adapter/regionserver"
	cidrrepo "github.com/tidbcloud/tidb-management-service/dedicated-global-service/domain/repository/cidr"
	regionrepo "github.com/tidbcloud/tidb-management-service/dedicated-global-service/domain/repository/region"
	"github.com/tidbcloud/tidb-management-service/dedicated-global-service/domain/service/workflow/common"
	"github.com/tidbcloud/tidb-management-service/utilities/bizerr"
	"github.com/tidbcloud/tidb-management-service/utilities/workflow"
)

const (
	AddSecondaryCidr = "add_secondary_cidr"
)

type AddSecondaryCidrAction struct {
	regionRepo      regionrepo.Repo
	cidrRepo        cidrrepo.Repo
	regionServerCli regionserver.Client
}

func NewAddSecondaryCidrAction(
	regionRepo regionrepo.Repo,
	cidrRepo cidrrepo.Repo,
	regionServerCli regionserver.Client,
) *AddSecondaryCidrAction {
	return &AddSecondaryCidrAction{
		regionRepo:      regionRepo,
		cidrRepo:        cidrRepo,
		regionServerCli: regionServerCli,
	}
}

func (a *AddSecondaryCidrAction) Name() string {
	return AddSecondaryCidr
}

func (a *AddSecondaryCidrAction) Run(ctx run.ExecuteContext, params any) error {
	cctx, span := workflow.GenerateContext(ctx)

	secondaryCidrId, ok := ctx.GetVar(common.KeySecondaryCidrId)
	if !ok {
		tilog.Error(cctx, "secondary_cidr_id parameter not found")
		return bizerr.New(bizerr.ErrCodeParams, "secondary_cidr_id parameter not found")
	}
	if secondaryCidrId == "" {
		tilog.Error(cctx, "secondary_cidr_id parameter is empty")
		return bizerr.New(bizerr.ErrCodeParams, "secondary_cidr_id parameter is empty")
	}

	cid, err := strconv.ParseUint(secondaryCidrId, 10, 64)
	if err != nil {
		tilog.Error(cctx, "failed to parse secondary_cidr_id", zap.Error(err))
		return err
	}

	tilog.Info(cctx, "start to add secondary cidr", zap.Uint64("secondary_cidr_id", cid))
	defer func() {
		tilog.Info(cctx, "end to add secondary cidr", zap.Uint64("secondary_cidr_id", cid))
		span.End()
	}()

	secondaryCidrs, err := a.cidrRepo.QuerySecondaryCidrs(cctx, &cidrrepo.Filter{
		IDs: []uint64{cid},
	}, nil)
	if err != nil {
		tilog.Error(cctx, "failed to query secondary_cidr", zap.Error(err))
		return err
	}
	if len(secondaryCidrs) == 0 {
		tilog.Error(cctx, "secondary_cidr not found")
		return bizerr.New(bizerr.ErrCodeParams, "secondary_cidr not found")
	}
	secondaryCidr := secondaryCidrs[0]

	regionEntity, err := a.regionRepo.SelectRegionById(
		cctx,
		secondaryCidr.BasicRegion.Name,
		secondaryCidr.TenantID,
	)
	if err != nil {
		return bizerr.WrapErrorWithCode(err, bizerr.ErrCodeParams, "invalid region")
	}
	addRequest := &regionaldedicatedv1.AddSecondaryCidrRequest{
		VpcId:         secondaryCidr.VpcID,
		SecondaryCidr: secondaryCidr.CIDR,
		ValidateOnly:  false,
	}
	if _, err := a.regionServerCli.AddSecondaryCidr(cctx, regionEntity, addRequest); err != nil {
		tilog.Error(cctx, "failed to add secondary cidr", zap.Error(err))
		return err
	}

	return nil
}
