package env

import (
	"context"

	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"sigs.k8s.io/controller-runtime/pkg/client"

	"github.com/tidbcloud/eks-provider/tests/e2e/dag"
	"github.com/tidbcloud/eks-provider/tests/e2e/data"
	"github.com/tidbcloud/eks-provider/tests/e2e/label"
	"github.com/tidbcloud/eks-provider/tests/e2e/suite"
	"github.com/tidbcloud/eks-provider/tests/e2e/utils/helper"
	"github.com/tidbcloud/eks-provider/tests/e2e/utils/wait"
	cloudv1 "github.com/tidbcloud/infra-api/api/v1"
)

func init() {
	suite.AddEnv(
		label.New(NewNetworkEnv(CloudAWS, InfraProviderVersionOld), "setup EKS with old infra provider"),
		label.New(NewNetworkEnv(CloudAWS, InfraProviderVersionNew), "setup EKS with new infra provider"),
		label.New(NewNetworkEnv(CloudGCP, InfraProviderVersionOld), "setup GKE with old infra provider"),
		label.New(NewNetworkEnv(CloudGCP, InfraProviderVersionNew), "setup GKE with new infra provider"),
	)
}

type NetworkEnv struct {
	Config    *Config
	Namespace *corev1.Namespace
	Network   *cloudv1.Network

	Reconciler string

	cloud string
	v     InfraProviderVersion
}

func NewNetworkEnv(cloud string, v InfraProviderVersion) dag.Env {
	return &NetworkEnv{
		cloud: cloud,
		v:     v,
	}
}

func (e *NetworkEnv) Name() string {
	return WithCloudAndVersion("Network", e.cloud, e.v)
}

func (e *NetworkEnv) Setup(ctx context.Context) error {
	if e.Config.ReuseNetwork != "" {
		net := cloudv1.Network{
			ObjectMeta: metav1.ObjectMeta{
				Name:      e.Config.ReuseNetwork,
				Namespace: e.Config.ReuseProject,
			},
		}

		if err := e.Config.InfraAPIClient.Get(ctx, client.ObjectKeyFromObject(&net), &net); err != nil {
			return err
		}
		e.Network = &net

		return nil
	}
	var cidr string

	switch e.v {
	case InfraProviderVersionOld:
		cidr = "10.1.0.0/16"
	case InfraProviderVersionNew:
		cidr = "10.2.0.0/16"
	default:
		panic("unreachable")
	}

	// TODO: create real network for test
	net := data.NewDefaultNetwork(e.Namespace.Name, e.cloud, e.Config.Region)
	if err := helper.Create(
		ctx,
		e.Config.InfraAPIClient,
		net,
		data.WithReconciler(e.Reconciler),
		data.NetworkWithCIDR(cidr),
	); err != nil {
		return err
	}

	if err := wait.WaitForNetworkPhase(ctx, e.Config.InfraAPIClient, net, cloudv1.NetworkPhaseNormal, wait.LongTaskTimeout); err != nil {
		return err
	}
	e.Network = net
	return nil
}

func (e *NetworkEnv) Envs() []string {
	return []string{
		WithCloudAndVersion("InfraProvider", e.cloud, e.v),
	}
}
