package byocvpcpeering

import (
	"fmt"
	"strconv"

	"github.com/samber/lo"

	globalcommonv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/common/v1"
	globalngv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/nextgen/v1"
	openapicommonv1beta1 "github.com/tidbcloud/tidb-management-service/api/spec/tidb_cloud_open_api/common/v1beta1"
	openapingv1beta2 "github.com/tidbcloud/tidb-management-service/api/spec/tidb_cloud_open_api/nextgen/v1beta2"
	"github.com/tidbcloud/tidb-management-service/tidb-mgmt-service/pkg/common"
	"github.com/tidbcloud/tidb-management-service/utilities/bizerr"
)

func cvtGlobalToOpenapiVpcPeering(peering *globalngv1.VpcPeering) *openapingv1beta2.VpcPeering {
	return &openapingv1beta2.VpcPeering{
		Name:               fmt.Sprintf("byoc/tidbs/%d/vpcPeerings/%s", peering.GetClusterId(), peering.GetId()),
		TidbId:             strconv.FormatUint(peering.GetClusterId(), 10),
		VpcPeeringId:       peering.GetId(),
		CloudProvider:      cvtCloudProvider(peering.GetCloudProviderId()),
		State:              cvtVpcPeeringState(peering.GetState()),
		TidbCloudRegionId:  peering.GetTidbCloudRegionId().String(),
		CustomerRegionId:   peering.GetCustomerRegionId().String(),
		TidbCloudAccountId: peering.GetTidbCloudAccountId(),
		CustomerAccountId:  peering.GetCustomerAccountId(),
		TidbCloudVpcId:     peering.GetTidbCloudVpcId(),
		CustomerVpcId:      peering.GetCustomerVpcId(),
		TidbCloudVpcCidr:   peering.GetTidbCloudVpcCidr(),
		CustomerVpcCidr:    peering.GetCustomerVpcCidr(),
	}
}

func cvtVpcPeeringState(state globalngv1.VpcPeering_State) openapingv1beta2.VpcPeering_State {
	switch state {
	case globalngv1.VpcPeering_PENDING:
		return openapingv1beta2.VpcPeering_PENDING
	case globalngv1.VpcPeering_FAILED:
		return openapingv1beta2.VpcPeering_FAILED
	case globalngv1.VpcPeering_ACTIVE:
		return openapingv1beta2.VpcPeering_ACTIVE
	default:
		return openapingv1beta2.VpcPeering_STATE_UNSPECIFIED
	}
}

func cvtCloudProvider(provider globalcommonv1.CloudProvider_Name) openapicommonv1beta1.Region_CloudProvider {
	return common.GlobalProviderToOpenApi(provider)
}

func cvtGlobalToOpenapiAllowlistSetting(setting *globalngv1.VpcPeeringAllowlistSetting) *openapingv1beta2.VpcPeeringAllowlistSetting {
	return &openapingv1beta2.VpcPeeringAllowlistSetting{
		Name:         fmt.Sprintf("byoc/tidbs/%d/vpcPeeringAllowlistSetting", setting.GetClusterId()),
		TidbId:       strconv.FormatUint(setting.GetClusterId(), 10),
		IpAccessList: cvtGlobalToOpenapiAllowlist(setting.GetIpAccessList()),
	}
}

func cvtGlobalToOpenapiAllowlist(in []*globalngv1.Endpoint_IpAddress) []*openapingv1beta2.VpcPeeringAllowlistSetting_IpAccessList {
	return lo.Map(in, func(each *globalngv1.Endpoint_IpAddress, _ int) *openapingv1beta2.VpcPeeringAllowlistSetting_IpAccessList {
		return &openapingv1beta2.VpcPeeringAllowlistSetting_IpAccessList{
			CidrNotation: each.GetCidrBlock(),
			Description:  each.GetDescription(),
		}
	})
}

func cvtOpenapiToGlobalAllowlist(in []*openapingv1beta2.VpcPeeringAllowlistSetting_IpAccessList) []*globalngv1.Endpoint_IpAddress {
	return lo.Map(in, func(each *openapingv1beta2.VpcPeeringAllowlistSetting_IpAccessList, _ int) *globalngv1.Endpoint_IpAddress {
		return &globalngv1.Endpoint_IpAddress{
			CidrBlock:   each.GetCidrNotation(),
			Description: each.GetDescription(),
		}
	})
}

func defaultAllowlistSetting(tidbID uint64) *openapingv1beta2.VpcPeeringAllowlistSetting {
	return &openapingv1beta2.VpcPeeringAllowlistSetting{
		Name:         fmt.Sprintf("byoc/tidbs/%d/vpcPeeringAllowlistSetting", tidbID),
		TidbId:       strconv.FormatUint(tidbID, 10),
		IpAccessList: []*openapingv1beta2.VpcPeeringAllowlistSetting_IpAccessList{},
	}
}

func wrapListError(err error) error {
	return bizerr.WrapErrorWithCode(err, bizerr.ErrCodeUnknown, "failed to list byoc vpc peerings")
}
