package scheme

import (
	vpcv1beta1 "github.com/aws/amazon-vpc-resource-controller-k8s/apis/vpcresources/v1beta1"
	pcav1beta1 "github.com/cert-manager/aws-privateca-issuer/pkg/api/v1beta1"
	autoscalingv1beta1 "github.com/crossplane-contrib/provider-aws/apis/autoscaling/v1beta1"
	ec2v1alpha1 "github.com/crossplane-contrib/provider-aws/apis/ec2/v1alpha1"
	ec2v1beta1 "github.com/crossplane-contrib/provider-aws/apis/ec2/v1beta1"
	"github.com/crossplane-contrib/provider-aws/apis/eks/manualv1alpha1"
	eksv1alpha1 "github.com/crossplane-contrib/provider-aws/apis/eks/v1alpha1"
	cpeksv1beta1 "github.com/crossplane-contrib/provider-aws/apis/eks/v1beta1"
	awsiamv1alpha1 "github.com/crossplane-contrib/provider-aws/apis/iam/v1alpha1"
	iamv1beta1 "github.com/crossplane-contrib/provider-aws/apis/iam/v1beta1"
	awskmsv1alpha1 "github.com/crossplane-contrib/provider-aws/apis/kms/v1alpha1"
	lambdav1alpha1 "github.com/crossplane-contrib/provider-aws/apis/lambda/v1alpha1"
	awsdnsv1alpha1 "github.com/crossplane-contrib/provider-aws/apis/route53/v1alpha1"
	s3v1alpha3 "github.com/crossplane-contrib/provider-aws/apis/s3/v1alpha3"
	s3v1beta1 "github.com/crossplane-contrib/provider-aws/apis/s3/v1beta1"
	cpawsv1beta1 "github.com/crossplane-contrib/provider-aws/apis/v1beta1"
	computev1alpha1 "github.com/crossplane-contrib/provider-gcp/apis/compute/v1alpha1"
	computev1beta1 "github.com/crossplane-contrib/provider-gcp/apis/compute/v1beta1"
	containerv1beta1 "github.com/crossplane-contrib/provider-gcp/apis/container/v1beta1"
	containerv1beta2 "github.com/crossplane-contrib/provider-gcp/apis/container/v1beta2"
	iamv1alpha1 "github.com/crossplane-contrib/provider-gcp/apis/iam/v1alpha1"
	storagev1alpha1 "github.com/crossplane-contrib/provider-gcp/apis/storage/v1alpha1"
	storagev1alpha3 "github.com/crossplane-contrib/provider-gcp/apis/storage/v1alpha3"
	gcpv1beta1 "github.com/crossplane-contrib/provider-gcp/apis/v1beta1"
	awsvpcpeeringv1alpha1 "github.com/crossplane/provider-aws/apis/vpcpeering/v1alpha1"
	gcpvpcpeeringv1beta1 "github.com/crossplane/provider-gcp/apis/vpcpeering/v1beta1"
	certmanagerv1 "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1"
	certmanagerv1alpha2 "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1alpha2"
	operatorv1alpha1 "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1"
	tiflowv1alpha1 "github.com/pingcap/tiflow-operator/api/v1alpha1"
	agentv1 "github.com/tidbcloud/observability/agent-control-server/api/v1"
	awsapis "github.com/upbound/provider-aws/apis"
	upboundec2v1beta1 "github.com/upbound/provider-aws/apis/ec2/v1beta1"
	eksv1beta1 "github.com/upbound/provider-aws/apis/eks/v1beta1"
	route53v1beta1 "github.com/upbound/provider-aws/apis/route53/v1beta1"
	awsv1beta1 "github.com/upbound/provider-aws/apis/v1beta1"
	azureapis "github.com/upbound/provider-azure/apis"
	azureauthv1beta1 "github.com/upbound/provider-azure/apis/authorization/v1beta1"
	azurev1beta1 "github.com/upbound/provider-azure/apis/azure/v1beta1"
	azurecontainerv1beta1 "github.com/upbound/provider-azure/apis/containerservice/v1beta1"
	azurenetworkv1beta1 "github.com/upbound/provider-azure/apis/network/v1beta1"
	upboundcomputev1beta1 "github.com/upbound/provider-gcp/apis/compute/v1beta1"
	upboundgcpcontainerv1beta1 "github.com/upbound/provider-gcp/apis/container/v1beta1"
	upbounddnsv1beta1 "github.com/upbound/provider-gcp/apis/dns/v1beta1"
	upboundgcpv1beta1 "github.com/upbound/provider-gcp/apis/v1beta1"
	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/serializer"
	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
	clientgoscheme "k8s.io/client-go/kubernetes/scheme"

	ackv1alpha1 "github.com/crossplane-contrib/provider-upjet-alibabacloud/apis/ack/v1alpha1"
	ramv1alpha1 "github.com/crossplane-contrib/provider-upjet-alibabacloud/apis/ram/v1alpha1"
	aliv1beta1 "github.com/crossplane-contrib/provider-upjet-alibabacloud/apis/v1beta1"

	"github.com/tidbcloud/eks-provider/api/v1alpha1"
	cloudv1 "github.com/tidbcloud/infra-api/api/v1"
	asts "github.com/tidbcloud/infra-provider/pkg/pingcap/apis/v1"
)

var (
	// Scheme is used for both infra api and data plane
	Scheme = runtime.NewScheme()
	Codecs = serializer.NewCodecFactory(Scheme)
)

func init() {
	loadCommonScheme()
	loadAWSScheme()
	loadGCPScheme()
	loadAzureScheme()
	loadAlicloudScheme()
	loadDataplaneScheme()
}

func loadCommonScheme() {
	utilruntime.Must(clientgoscheme.AddToScheme(Scheme))
	utilruntime.Must(cloudv1.SchemeBuilder.AddToScheme(Scheme))
	utilruntime.Must(v1alpha1.SchemeBuilder.AddToScheme(Scheme))
	utilruntime.Must(agentv1.SchemeBuilder.AddToScheme(Scheme))
	utilruntime.Must(operatorv1alpha1.SchemeBuilder.AddToScheme(Scheme))
}

func loadAWSScheme() {
	utilruntime.Must(s3v1beta1.SchemeBuilder.AddToScheme(Scheme))
	utilruntime.Must(s3v1alpha3.SchemeBuilder.AddToScheme(Scheme))
	utilruntime.Must(cpeksv1beta1.SchemeBuilder.AddToScheme(Scheme))
	utilruntime.Must(cpawsv1beta1.SchemeBuilder.AddToScheme(Scheme))
	utilruntime.Must(lambdav1alpha1.SchemeBuilder.AddToScheme(Scheme))
	utilruntime.Must(ec2v1alpha1.SchemeBuilder.AddToScheme(Scheme))
	utilruntime.Must(ec2v1beta1.SchemeBuilder.AddToScheme(Scheme))
	utilruntime.Must(awskmsv1alpha1.SchemeBuilder.AddToScheme(Scheme))
	utilruntime.Must(manualv1alpha1.SchemeBuilder.AddToScheme(Scheme))
	utilruntime.Must(awsvpcpeeringv1alpha1.SchemeBuilder.AddToScheme(Scheme))
	utilruntime.Must(awsdnsv1alpha1.SchemeBuilder.AddToScheme(Scheme))
	utilruntime.Must(awsiamv1alpha1.SchemeBuilder.AddToScheme(Scheme))
	utilruntime.Must(iamv1beta1.SchemeBuilder.AddToScheme(Scheme))
	utilruntime.Must(autoscalingv1beta1.SchemeBuilder.AddToScheme(Scheme))
	utilruntime.Must(eksv1alpha1.SchemeBuilder.AddToScheme(Scheme))
	// upbound aws scheme
	utilruntime.Must(awsapis.AddToScheme(Scheme))
	utilruntime.Must(awsv1beta1.SchemeBuilder.AddToScheme(Scheme))
	utilruntime.Must(upboundec2v1beta1.AddToScheme(Scheme))
	utilruntime.Must(eksv1beta1.AddToScheme(Scheme))
	utilruntime.Must(route53v1beta1.AddToScheme(Scheme))
}

func loadGCPScheme() {
	utilruntime.Must(computev1alpha1.SchemeBuilder.AddToScheme(Scheme))
	utilruntime.Must(computev1beta1.SchemeBuilder.AddToScheme(Scheme))
	utilruntime.Must(containerv1beta1.SchemeBuilder.AddToScheme(Scheme)) // nodepool is v1beta1
	utilruntime.Must(containerv1beta2.SchemeBuilder.AddToScheme(Scheme)) // cluster is v1beta2
	utilruntime.Must(gcpv1beta1.SchemeBuilder.AddToScheme(Scheme))
	utilruntime.Must(iamv1alpha1.SchemeBuilder.AddToScheme(Scheme))
	utilruntime.Must(storagev1alpha1.SchemeBuilder.AddToScheme(Scheme))
	utilruntime.Must(storagev1alpha3.SchemeBuilder.AddToScheme(Scheme))
	utilruntime.Must(gcpvpcpeeringv1beta1.SchemeBuilder.AddToScheme(Scheme))
	utilruntime.Must(upboundgcpv1beta1.SchemeBuilder.AddToScheme(Scheme))
	utilruntime.Must(upboundgcpcontainerv1beta1.AddToScheme(Scheme))
	utilruntime.Must(upbounddnsv1beta1.AddToScheme(Scheme))
	utilruntime.Must(upboundcomputev1beta1.AddToScheme(Scheme))
}

func loadAzureScheme() {
	utilruntime.Must(azureapis.AddToScheme(Scheme)) // All crossplane Azure schemes
	utilruntime.Must(azurev1beta1.AddToScheme(Scheme))
	utilruntime.Must(azurenetworkv1beta1.AddToScheme(Scheme))
	utilruntime.Must(azurecontainerv1beta1.AddToScheme(Scheme))
	utilruntime.Must(azureauthv1beta1.AddToScheme(Scheme))
}

func loadAlicloudScheme() {
	utilruntime.Must(aliv1beta1.SchemeBuilder.AddToScheme(Scheme))
	utilruntime.Must(ackv1alpha1.SchemeBuilder.AddToScheme(Scheme))
	utilruntime.Must(ramv1alpha1.SchemeBuilder.AddToScheme(Scheme))
}

type addToSchemeFunc func(s *runtime.Scheme) error

func loadSchemes(schemeFuncs []addToSchemeFunc) {
	for _, f := range schemeFuncs {
		utilruntime.Must(f(Scheme))
	}
}

func loadDataplaneScheme() {
	schemeFuncs := []addToSchemeFunc{
		clientgoscheme.AddToScheme,
		certmanagerv1alpha2.AddToScheme,
		certmanagerv1.AddToScheme,
		pcav1beta1.AddToScheme,
		asts.AddToScheme,
		operatorv1alpha1.AddToScheme,
		tiflowv1alpha1.AddToScheme,
		apiextensionsv1.AddToScheme,
		vpcv1beta1.AddToScheme,
	}
	loadSchemes(schemeFuncs)
}
