package data

import (
	"fmt"

	ec2v1alpha1 "github.com/crossplane-contrib/provider-aws/apis/ec2/v1alpha1"
	ec2v1beta1 "github.com/crossplane-contrib/provider-aws/apis/ec2/v1beta1"
	lambdav1beta1 "github.com/crossplane-contrib/provider-aws/apis/lambda/v1beta1"
	"github.com/crossplane-contrib/provider-aws/apis/v1beta1"
	xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/utils/pointer"

	"github.com/tidbcloud/eks-provider/tests/e2e/types"
	cloudv1 "github.com/tidbcloud/infra-api/api/v1"
)

func ProviderConfigName(ident string) string {
	return types.EndUserAWSResource.Namer().Name()
}

func NewProviderConfig(_ string, acct *cloudv1.Account) *v1beta1.ProviderConfig {
	name := types.EndUserAWSResource.Namer().Name()
	return &v1beta1.ProviderConfig{
		ObjectMeta: metav1.ObjectMeta{
			Name: name,
		},
		Spec: v1beta1.ProviderConfigSpec{
			AssumeRoleARN: &acct.Spec.AWS.AssumeRoleARN,
			ExternalID:    acct.Spec.AWS.ExternalID,
			Credentials: v1beta1.ProviderCredentials{
				Source: xpv1.CredentialsSourceInjectedIdentity,
			},
		},
	}
}

func NewEndUserVPC(ident, region string) *ec2v1beta1.VPC {
	return &ec2v1beta1.VPC{
		ObjectMeta: metav1.ObjectMeta{
			Name: types.EndUserAWSResource.Namer().Name(),
		},
		Spec: ec2v1beta1.VPCSpec{
			ResourceSpec: xpv1.ResourceSpec{
				ProviderConfigReference: &xpv1.Reference{
					Name: ProviderConfigName(ident),
				},
			},
			ForProvider: ec2v1beta1.VPCParameters{
				Region:             pointer.String(region),
				CIDRBlock:          "192.168.0.0/22",
				EnableDNSSupport:   pointer.Bool(true),
				EnableDNSHostNames: pointer.Bool(true),
			},
		},
	}
}

var zoneSuffix = [...]string{"a", "b", "c"}

func NewEndUserSubnet(ident, region string, index int) *ec2v1beta1.Subnet {
	zone := region + zoneSuffix[index]
	return &ec2v1beta1.Subnet{
		ObjectMeta: metav1.ObjectMeta{
			Name: types.EndUserAWSZonalResource.Namer(zone).Name(),
		},
		Spec: ec2v1beta1.SubnetSpec{
			ResourceSpec: xpv1.ResourceSpec{
				ProviderConfigReference: &xpv1.Reference{
					Name: ProviderConfigName(ident),
				},
			},
			ForProvider: ec2v1beta1.SubnetParameters{
				CIDRBlock: fmt.Sprintf("192.168.%d.0/24", index),
				VPCIDRef: &xpv1.Reference{
					Name: types.EndUserAWSResource.Namer().Name(),
				},
				AvailabilityZone: &zone,
			},
		},
	}
}

func NewEndUserSecurityGroup(ident string) *ec2v1beta1.SecurityGroup {
	name := types.EndUserAWSResource.Namer().Name()
	return &ec2v1beta1.SecurityGroup{
		ObjectMeta: metav1.ObjectMeta{
			Name: name,
		},
		Spec: ec2v1beta1.SecurityGroupSpec{
			ResourceSpec: xpv1.ResourceSpec{
				ProviderConfigReference: &xpv1.Reference{
					Name: ProviderConfigName(ident),
				},
			},
			ForProvider: ec2v1beta1.SecurityGroupParameters{
				Description: "for infra provider e2e, please @liubo02",
				GroupName:   name,
				VPCIDRef: &xpv1.Reference{
					Name: name,
				},
				Ingress: []ec2v1beta1.IPPermission{
					{
						IPProtocol: "-1",
						IPRanges: []ec2v1beta1.IPRange{
							{
								CIDRIP: "0.0.0.0/0",
							},
						},
					},
				},
				Egress: []ec2v1beta1.IPPermission{
					{
						IPProtocol: "-1",
						IPRanges: []ec2v1beta1.IPRange{
							{
								CIDRIP: "0.0.0.0/0",
							},
						},
					},
				},
			},
		},
	}
}

func NewVPCEndpoint(region, svcName string) *ec2v1alpha1.VPCEndpoint {
	refs := []xpv1.Reference{}
	zones := getZones(region)
	for _, zone := range zones {
		refs = append(refs, xpv1.Reference{
			Name: types.EndUserAWSZonalResource.Namer(zone).Name(),
		})
	}
	return &ec2v1alpha1.VPCEndpoint{
		ObjectMeta: metav1.ObjectMeta{
			Name: svcName,
		},
		Spec: ec2v1alpha1.VPCEndpointSpec{
			ResourceSpec: xpv1.ResourceSpec{
				ProviderConfigReference: &xpv1.Reference{
					Name: ProviderConfigName(""),
				},
			},
			ForProvider: ec2v1alpha1.VPCEndpointParameters{
				Region:          region,
				ServiceName:     &svcName,
				VPCEndpointType: pointer.String("Interface"),
				CustomVPCEndpointParameters: ec2v1alpha1.CustomVPCEndpointParameters{
					VPCIDRef: &xpv1.Reference{
						Name: types.EndUserAWSResource.Namer().Name(),
					},
					SubnetIDRefs: refs,
					SecurityGroupIDRefs: []xpv1.Reference{
						{
							Name: types.EndUserAWSResource.Namer().Name(),
						},
					},
				},
			},
		},
	}
}

func NewEndUserLambda(ident string, region string) *lambdav1beta1.Function {
	name := types.EndUserAWSResource.Namer().Name()

	refs := []xpv1.Reference{}
	zones := getZones(region)
	for _, zone := range zones {
		refs = append(refs, xpv1.Reference{
			Name: types.EndUserAWSZonalResource.Namer(zone).Name(),
		})
	}
	image := "200683210682.dkr.ecr.us-west-2.amazonaws.com/tidbcloud/e2e/end-user-proxy:latest"

	cmds := []*string{
		pointer.String("/end-user-proxy"),
	}
	return &lambdav1beta1.Function{
		ObjectMeta: metav1.ObjectMeta{
			Name: name,
		},
		Spec: lambdav1beta1.FunctionSpec{
			ResourceSpec: xpv1.ResourceSpec{
				ProviderConfigReference: &xpv1.Reference{
					Name: ProviderConfigName(ident),
				},
			},
			ForProvider: lambdav1beta1.FunctionParameters{
				PackageType: pointer.String("Image"),
				ImageConfig: &lambdav1beta1.ImageConfig{
					Command: cmds,
				},
				Region:  region,
				Publish: pointer.Bool(true),
				CustomFunctionParameters: lambdav1beta1.CustomFunctionParameters{
					RoleRef: &xpv1.Reference{
						Name: "e2e-lambda-test",
					},
					CustomFunctionCodeParameters: lambdav1beta1.CustomFunctionCodeParameters{
						ImageURI: &image,
					},
					CustomFunctionVPCConfigParameters: &lambdav1beta1.CustomFunctionVPCConfigParameters{
						SubnetIDRefs: refs,
						SecurityGroupIDRefs: []xpv1.Reference{
							{
								Name: types.EndUserAWSResource.Namer().Name(),
							},
						},
					},
				},
			},
		},
	}
}

func getZones(region string) []string {
	zones := make([]string, 0, len(zoneSuffix))
	for _, suffix := range zoneSuffix {
		zones = append(zones, region+suffix)
	}
	return zones
}
