package framework

import (
	"fmt"
	"log"
	"os"
	"time"

	ginkgo "github.com/onsi/ginkgo/v2"
	. "github.com/onsi/gomega"
	runtime "k8s.io/apimachinery/pkg/runtime"
	"k8s.io/client-go/kubernetes/scheme"
	"k8s.io/client-go/tools/clientcmd"
	"sigs.k8s.io/controller-runtime/pkg/client"

	ec2v1beta1 "github.com/crossplane/provider-aws/apis/ec2/v1beta1"

	cloudv1 "github.com/tidbcloud/infra-api/api/v1"
	"github.com/tidbcloud/infra-api/test/e2ev2/provider"
)

const (
	DefaultNetworkCreateTimeout        = 25 * time.Minute
	DefaultNetworkDeleteTimeout        = 25 * time.Minute
	DefaultClusterCreateTimeout        = 10 * time.Minute
	DefaultClusterDeleteTimeout        = 10 * time.Minute
	DefaultInterval                    = 5 * time.Second
	DefaultNetworkPeeringActiveTimeout = 10 * time.Minute
	DefaultCDCDeleteTimeout            = 10 * time.Minute
	DefaultCDCCreateTimeout            = 10 * time.Minute
)

var (
	DefaultFramework *Framework = new(Framework)
)

type Framework struct {
	TestContext
	InfraCli           client.Client
	Scheme             *runtime.Scheme
	Provider           provider.Provider
	SupportCrossRegion bool
}

type TestContext struct {
	Interval                    time.Duration
	NetworkCreateTimeout        time.Duration
	NetworkDeleteTimeout        time.Duration
	ClusterCreateTimeout        time.Duration
	ClusterDeleteTimeout        time.Duration
	CDCCreateTimeout            time.Duration
	CDCDeleteTimeout            time.Duration
	NetworkPeeringActiveTimeout time.Duration
}

func init() {
	restConfig, err := clientcmd.BuildConfigFromFlags("", os.Getenv("KUBECONFIG"))
	if err != nil {
		log.Fatal(err)
	}

	scheme := scheme.Scheme
	err = cloudv1.AddToScheme(scheme)
	if err != nil {
		log.Fatal(err)
	}
	err = ec2v1beta1.SchemeBuilder.AddToScheme(scheme)
	if err != nil {
		log.Fatal(err)
	}
	infraCli, err := client.New(restConfig, client.Options{
		Scheme: scheme,
	})

	if err != nil {
		log.Fatal(err)
	}

	f := DefaultFramework
	f.TestContext = TestContext{
		Interval:                    DefaultInterval,
		NetworkCreateTimeout:        DefaultNetworkCreateTimeout,
		NetworkDeleteTimeout:        DefaultNetworkDeleteTimeout,
		ClusterCreateTimeout:        DefaultClusterCreateTimeout,
		ClusterDeleteTimeout:        DefaultClusterDeleteTimeout,
		NetworkPeeringActiveTimeout: DefaultNetworkPeeringActiveTimeout,
		CDCCreateTimeout:            DefaultCDCCreateTimeout,
		CDCDeleteTimeout:            DefaultCDCDeleteTimeout,
	}
	f.InfraCli = infraCli
	f.Scheme = scheme
}

func (f *Framework) RegisterProvider(p provider.Provider) {
	f.Provider = p
}

func (f *Framework) ExpectNoError(actul interface{}, optionalDescription ...interface{}) {
	Expect(actul).Should(Succeed(), optionalDescription...)
}

func (f *Framework) Log(format string, args ...interface{}) {
	fmt.Fprintf(ginkgo.GinkgoWriter, format+"\n", args...)
}
