package publicconnectionsetting

import (
	"context"
	"strconv"

	"github.com/samber/lo"
	"github.com/tidbcloud/tiinf/sdk/auditlog"

	globalngv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/nextgen/v1"
	openapingv1beta2 "github.com/tidbcloud/tidb-management-service/api/spec/tidb_cloud_open_api/nextgen/v1beta2"
	"github.com/tidbcloud/tidb-management-service/tidb-mgmt-service/domain/adapter/eventbus"
	"github.com/tidbcloud/tidb-management-service/utilities/bizerr"
	"github.com/tidbcloud/tidb-management-service/utilities/grpc/metadata"
)

func (s *serverImpl) UpdatePublicConnectionSetting(
	ctx context.Context,
	req *openapingv1beta2.UpdatePublicConnectionSettingRequest,
) (*openapingv1beta2.PublicConnectionSetting, error) {
	ctx, span := tracer.Start(ctx, "UpdatePublicConnectionSetting")
	defer span.End()

	tidbId, err := strconv.ParseUint(req.TidbId, 10, 64)
	if err != nil {
		return nil, bizerr.WrapErrorWithCode(err, bizerr.ErrCodeParams, "invalid tidb id")
	}

	reqSetting := req.GetPublicConnectionSetting()
	if reqSetting == nil {
		return nil, bizerr.New(bizerr.ErrCodeParams, "public connection setting is required")
	}

	var (
		reqMeta *metadata.RequestMeta
	)

	detailsFunc := func() auditlog.Details {
		details := eventbus.NewAuditLogDetails(eventbus.TierTypePremium)
		details[auditlog.KeyIPAllowlist] = req.GetPublicConnectionSetting().GetIpAccessList()
		details[auditlog.KeyEnableOrDisable] = req.GetPublicConnectionSetting().GetEnabled()
		return details
	}
	defer func() {
		s.auditLogSender.SubmitAuditLogForNextgen(ctx, auditlog.EventUpdatePublicConnection, reqMeta, detailsFunc, err)
	}()

	// Extract request meta.
	reqMeta, err = metadata.ExtractRequestMetaWithCheckPermission(ctx)
	if err != nil {
		return nil, bizerr.WrapErrorWithCode(err, bizerr.ErrCodeParams, "failed to extract request metadata")
	}

	setting, err := s.nextgenCli.UpdatePublicConnectionSetting(
		ctx,
		&globalngv1.UpdatePublicConnectionSettingRequest{
			PublicConnectionSetting: &globalngv1.PublicConnectionSetting{
				ClusterId:        tidbId,
				Enable:           reqSetting.Enabled,
				IpAllowList:      cvtOpenapiToGlobalPublicConnectionSettingIpAccessList(reqSetting.GetIpAccessList()),
				ClearIpAllowList: reqSetting.ClearIpAccessList,
			},
		},
	)
	if err != nil {
		return nil, bizerr.WrapErrorWithCode(err, bizerr.ErrCodeUnknown, "failed to update public connection setting")
	}

	return cvtGlobalToOpenapiPublicConnectionSetting(setting), nil
}

func cvtOpenapiToGlobalPublicConnectionSettingIpAccessList(
	ipAccessList []*openapingv1beta2.PublicConnectionSetting_IpAccessList,
) []*globalngv1.Endpoint_IpAddress {
	return lo.Map(
		ipAccessList,
		func(ipAccessList *openapingv1beta2.PublicConnectionSetting_IpAccessList, _ int) *globalngv1.Endpoint_IpAddress {
			return &globalngv1.Endpoint_IpAddress{
				CidrBlock:   ipAccessList.CidrNotation,
				Description: ipAccessList.Description,
			}
		},
	)
}
