package eks

import (
	"context"
	"testing"
	"time"

	"github.com/crossplane-contrib/provider-aws/apis/ec2/v1beta1"
	xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1"
	"github.com/stretchr/testify/assert"
	cloudv1 "github.com/tidbcloud/infra-api/api/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/types"
	"k8s.io/utils/pointer"

	"github.com/tidbcloud/infra-provider/pkg/deploy"
	"github.com/tidbcloud/infra-provider/pkg/util"
	"github.com/tidbcloud/infra-provider/regional-server/api/v1alpha1"
)

func fakeInternetGatewayTask(t *testing.T) *InternetGatway {
	c := fakeTaskContext(t)
	igTask := NewInternetGateway(c)
	return igTask
}

func TestInternetGateway_Create(t *testing.T) {
	t.Run("create internet gateway success", func(t *testing.T) {
		igTask := fakeInternetGatewayTask(t)
		tags := cloudv1.TagsFromLabels(igTask.Internet.Labels)
		result := igTask.Create(context.Background())
		assert.True(t, result.IsDoneState())
		igRes := &v1beta1.InternetGateway{}
		igResName := igTask.internetGatewayName()
		err := igTask.Local.Get(context.Background(), types.NamespacedName{Name: igResName}, igRes)
		assert.Nil(t, err)
		assert.Equal(t, v1beta1.InternetGatewaySpec{
			ResourceSpec: xpv1.ResourceSpec{
				ProviderConfigReference: &xpv1.Reference{Name: igTask.ProviderConfigName()},
			},
			ForProvider: v1beta1.InternetGatewayParameters{
				Region: pointer.String(igTask.Internet.Spec.Region),
				VPCIDRef: &xpv1.Reference{
					Name: igTask.VPC.Status.VPC.Name,
				},
				Tags: util.GetEC2V1BetaTags(tags),
			},
		}, igRes.Spec)
	})
}

func TestInternetGateway_PostCreate(t *testing.T) {
	t.Run("create internet gateway success", func(t *testing.T) {
		igTask := fakeInternetGatewayTask(t)
		result := igTask.Create(context.Background())
		assert.True(t, result.IsDoneState())
		igRes := &v1beta1.InternetGateway{}
		igResName := igTask.internetGatewayName()
		err := igTask.Local.Get(context.Background(), types.NamespacedName{Name: igResName}, igRes)
		igRes.Status.AtProvider.Attachments = []v1beta1.InternetGatewayAttachment{
			{
				VPCID:            igTask.VPC.Status.VPC.VPCID,
				AttachmentStatus: "available",
			},
		}
		igRes.Status.AtProvider.InternetGatewayID = "ig-123456"
		assert.Nil(t, igTask.Local.Status().Update(context.Background(), igRes))
		assert.Nil(t, err)
		result = igTask.PostCreate(context.Background())
		assert.True(t, result.IsDoneState())
	})
	t.Run("aws ig not found", func(t *testing.T) {
		igTask := fakeInternetGatewayTask(t)
		result := igTask.PostCreate(context.Background())
		res, err, retriableErr := deploy.MinRequeue([]deploy.Result{result})
		assert.Nil(t, err)
		assert.ErrorContains(t, retriableErr, "not found")
		assert.Equal(t, time.Second*30, res.RequeueAfter)
	})
}

func TestInternetGateway_setInternetGatewayStatus(t *testing.T) {
	igTask := fakeInternetGatewayTask(t)
	igResName := "ig-test"
	igId := "ig-123456"
	igRes := &v1beta1.InternetGateway{
		ObjectMeta: metav1.ObjectMeta{
			Name: igResName,
		},
		Status: v1beta1.InternetGatewayStatus{
			AtProvider: v1beta1.InternetGatewayObservation{
				InternetGatewayID: igId,
			},
		},
	}
	t.Run("Set ig info to vpc status", func(t *testing.T) {
		err := igTask.setInternetGatewayStatus(context.Background(), igRes)
		assert.Nil(t, err)
		assert.Equal(t, v1alpha1.InternetGateway{
			Name:              igResName,
			InternetGatewayID: igId,
		}, igTask.Internet.Status.InternetGateway)
	})
}

func TestInternetGateway_Delete(t *testing.T) {
	igTask := fakeInternetGatewayTask(t)
	t.Run("Delete aws ig success", func(t *testing.T) {
		result := igTask.Create(context.Background())
		assert.True(t, result.IsDoneState())
		result = igTask.Delete(context.Background())
		assert.True(t, result.IsDoneState())
	})
	t.Run("Delete aws ig not found", func(t *testing.T) {
		result := igTask.Delete(context.Background())
		assert.True(t, result.IsDoneState())
	})
}

func TestInternetGateway_PostDelete(t *testing.T) {
	igTask := fakeInternetGatewayTask(t)
	t.Run("Delete aws ig success", func(t *testing.T) {
		result := igTask.Create(context.Background())
		assert.True(t, result.IsDoneState())
		result = igTask.Delete(context.Background())
		assert.True(t, result.IsDoneState())
		result = igTask.PostDelete(context.Background())
		assert.True(t, result.IsDoneState())
	})
	t.Run("Delete aws ig not found", func(t *testing.T) {
		result := igTask.PostDelete(context.Background())
		assert.True(t, result.IsDoneState())
	})
}
