package internet

import (
	"bytes"
	"context"
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/gin-gonic/gin"
	"github.com/stretchr/testify/assert"
	"github.com/tidbcloud/infra-provider/pkg/consts"
	"github.com/tidbcloud/infra-provider/regional-server/api/v1alpha1"
	"github.com/tidbcloud/infra-provider/regional-server/pkg/common/message"
	"github.com/tidbcloud/infra-provider/regional-server/pkg/config"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"sigs.k8s.io/controller-runtime/pkg/client/fake"
)

func TestCreateInternet(t *testing.T) {
	gin.SetMode(gin.TestMode)
	eng := gin.Default()
	s := runtime.NewScheme()
	v1alpha1.AddToScheme(s)
	mockcli := fake.NewClientBuilder().WithScheme(s).Build()
	handler := NewInternetHandler(mockcli, config.RootConfig{
		ControllerConfig: config.ControllerConfig{
			Provider: consts.ProviderTypeEKS,
		},
	})
	t.Run("request is not valid", func(t *testing.T) {
		in := &message.CreateInternetReq{}
		buf, err := json.Marshal(in)
		assert.Nil(t, err)
		body := bytes.NewReader(buf)
		w := httptest.NewRecorder()
		ctx := gin.CreateTestContextOnly(w, eng)
		ctx.Request = httptest.NewRequest("POST", "/api/dedicated/v1/internets", body)
		handler.CreateInternet(ctx)
		assert.Equal(t, http.StatusBadRequest, w.Result().StatusCode)
	})
	t.Run("create internet failed", func(t *testing.T) {
		in := &message.CreateInternetReq{
			VPCID: "1",
		}
		buf, err := json.Marshal(in)
		assert.Nil(t, err)
		body := bytes.NewReader(buf)
		w := httptest.NewRecorder()
		ctx := gin.CreateTestContextOnly(w, eng)
		ctx.Request = httptest.NewRequest("POST", "/api/dedicated/v1/internets", body)
		handler.CreateInternet(ctx)
		assert.Equal(t, http.StatusNotFound, w.Result().StatusCode)
	})
	t.Run("create internet success", func(t *testing.T) {
		assert.Nil(t, mockcli.Create(context.Background(), &v1alpha1.VPC{
			ObjectMeta: metav1.ObjectMeta{
				Name:      "vcp-test",
				Namespace: "test",
				Labels: map[string]string{
					v1alpha1.VPCIDKey: "vpc-123",
				},
			},
		}))
		in := &message.CreateInternetReq{
			VPCID: "vpc-123",
		}
		buf, err := json.Marshal(in)
		assert.Nil(t, err)
		body := bytes.NewReader(buf)
		w := httptest.NewRecorder()
		ctx := gin.CreateTestContextOnly(w, eng)
		ctx.Request = httptest.NewRequest("POST", "/api/dedicated/v1/internets", body)
		handler.CreateInternet(ctx)
		assert.Equal(t, http.StatusAccepted, w.Result().StatusCode)
	})
}

func TestDeleteInternet(t *testing.T) {
	gin.SetMode(gin.TestMode)
	eng := gin.Default()
	s := runtime.NewScheme()
	v1alpha1.AddToScheme(s)
	mockcli := fake.NewClientBuilder().WithScheme(s).Build()
	handler := NewInternetHandler(mockcli, config.RootConfig{
		ControllerConfig: config.ControllerConfig{
			Provider: consts.ProviderTypeEKS,
		},
	})
	t.Run("request is not valid", func(t *testing.T) {
		w := httptest.NewRecorder()
		ctx := gin.CreateTestContextOnly(w, eng)
		ctx.Request = httptest.NewRequest("DELETE", "/api/dedicated/v1/internets/test/internet-test", nil)
		handler.DeleteInternet(ctx)
		assert.Equal(t, http.StatusBadRequest, w.Result().StatusCode)
	})
	t.Run("delete internet success", func(t *testing.T) {
		assert.Nil(t, mockcli.Create(context.Background(), &v1alpha1.Internet{
			ObjectMeta: metav1.ObjectMeta{
				Name:      "internet-test",
				Namespace: "test",
			}}))
		w := httptest.NewRecorder()
		ctx := gin.CreateTestContextOnly(w, eng)
		ctx.Request = httptest.NewRequest("DELETE", "/api/dedicated/v1/internets/test/internet-test", nil)
		ctx.Params = []gin.Param{
			{
				Key:   "name",
				Value: "internet-test",
			},
			{
				Key:   "namespace",
				Value: "test",
			},
		}
		handler.DeleteInternet(ctx)
		assert.Equal(t, http.StatusOK, w.Result().StatusCode)

		// delete again
		handler.DeleteInternet(ctx)
		assert.Equal(t, http.StatusOK, w.Result().StatusCode)
	})
}

func TestGetInternet(t *testing.T) {
	gin.SetMode(gin.TestMode)
	eng := gin.Default()
	s := runtime.NewScheme()
	v1alpha1.AddToScheme(s)
	mockcli := fake.NewClientBuilder().WithScheme(s).Build()
	handler := NewInternetHandler(mockcli, config.RootConfig{
		ControllerConfig: config.ControllerConfig{
			Provider: consts.ProviderTypeEKS,
		},
	})
	t.Run("request is not valid", func(t *testing.T) {
		w := httptest.NewRecorder()
		ctx := gin.CreateTestContextOnly(w, eng)
		ctx.Request = httptest.NewRequest("GET", "/api/dedicated/v1/internets/test/internet-test", nil)
		handler.GetInternet(ctx)
		assert.Equal(t, http.StatusBadRequest, w.Result().StatusCode)
	})
	t.Run("get internet success", func(t *testing.T) {
		assert.Nil(t, mockcli.Create(context.Background(), &v1alpha1.Internet{
			ObjectMeta: metav1.ObjectMeta{
				Name:      "internet-test",
				Namespace: "test",
			},
		}))
		w := httptest.NewRecorder()
		ctx := gin.CreateTestContextOnly(w, eng)
		ctx.Request = httptest.NewRequest("GET", "/api/dedicated/v1/internets/test/internet-test", nil)
		ctx.Params = []gin.Param{
			{
				Key:   "name",
				Value: "internet-test",
			},
			{
				Key:   "namespace",
				Value: "test",
			},
		}
		handler.GetInternet(ctx)
		assert.Equal(t, http.StatusOK, w.Result().StatusCode)
	})
}
