package handler

import (
	"fmt"
	"net/http"
	"testing"

	"github.com/stretchr/testify/assert"

	"github.com/pingcap/test-infra/common/model"
	reqM "github.com/pingcap/test-infra/common/model/tcms/request"
	respM "github.com/pingcap/test-infra/common/model/tcms/response"
	htest "github.com/pingcap/test-infra/services/tcms/tests/httptest"
)

func newResourceCohort() *reqM.ResourceCohortCreateRequest {
	return &reqM.ResourceCohortCreateRequest{
		Name:    "newCohort",
		Summary: "Create new cohort.",
		Resourcepools: []*reqM.ResourceCohortAddPoolRequest{
			{Name: "rp_name0"},
			{Name: "rp_name1"},
			{Name: "rp_name2"},
		},
	}
}

func checkDefaultCohortPool(t *testing.T, pools []*model.ResourceCohortPool) {
	assert.Len(t, pools, 2)
	for _, pool := range pools {
		switch pool.Name {
		case "default":
			assert.Len(t, pool.BorrowedPolicy, 2)
		case "ksyun-default":
			assert.Len(t, pool.BorrowedPolicy, 1)
		default:
			assert.FailNow(t, "unexpected resourcepool %s", pool.Name)
		}
	}
}

func TestHTTPHandler_ListResourceCohorts(t *testing.T) {
	h := setup(t)
	defer h.Shutdown()

	_, cohorts := htest.MustGET[respM.ResourceCohortListResponse](h.Echo, "/api/v1/resource-cohorts")
	assert.Equal(t, 2, cohorts.Total)

	_, cohorts = htest.MustGET[respM.ResourceCohortListResponse](h.Echo, "/api/v1/resource-cohorts?resourcepool=default")
	assert.Equal(t, 1, cohorts.Total)
	cohort := cohorts.Data[0]
	assert.Equal(t, model.ID(1), cohort.ID)
	assert.Equal(t, "default", cohort.Name)
	checkDefaultCohortPool(t, cohort.Resourcepools)
}

func TestHTTPHandler_GetResourceCohort(t *testing.T) {
	h := setup(t)
	defer h.Shutdown()

	_, cohort := htest.MustGET[model.ResourceCohort](h.Echo, "/api/v1/resource-cohorts/default")
	assert.Equal(t, "default", cohort.Name)
	checkDefaultCohortPool(t, cohort.Resourcepools)

	_, cohort = htest.MustGET[model.ResourceCohort](h.Echo, "/api/v1/resource-cohorts/fake")
	assert.Equal(t, "fake", cohort.Name)
	assert.Len(t, cohort.Resourcepools, 0)
}

func TestHTTPHandler_CreateResourceCohort(t *testing.T) {
	h := setup(t)
	defer h.Shutdown()

	newCohort := newResourceCohort()
	_, _ = htest.MustPOST[any](h.Echo, "/api/v1/resource-cohorts", htest.WithJSON(newCohort))

	_, cohort := htest.MustGET[model.ResourceCohort](h.Echo, "/api/v1/resource-cohorts/"+newCohort.Name)
	assert.Equal(t, newCohort.Name, cohort.Name)
	assert.Equal(t, newCohort.Summary, cohort.Summary)

	// check respool
	newRespools := []string{}
	for _, pool := range newCohort.Resourcepools {
		newRespools = append(newRespools, pool.Name)
	}
	respools := cohort.Resourcepools
	assert.Len(t, respools, len(newRespools))
	for _, pool := range respools {
		assert.NotZero(t, pool.ID)
		assert.Contains(t, newRespools, pool.Name)
		assert.NotZero(t, len(pool.BorrowedPolicy))
	}
}

func TestHTTPHandler_DeleteResourceCohort(t *testing.T) {
	h := setup(t)
	defer h.Shutdown()

	name := "default"
	_, _ = htest.MustGET[model.ResourceCohort](h.Echo, "/api/v1/resource-cohorts/"+name)
	_, _ = htest.MustDELETE[any](h.Echo, "/api/v1/resource-cohorts/"+name)
	resp, _ := htest.GET[model.ResourceCohort](h.Echo, "/api/v1/resource-cohorts/"+name)
	assert.Equal(t, http.StatusNotFound, resp.Code)
}

func TestHTTPHandler_AddPool2ResourceCohort(t *testing.T) {
	h := setup(t)
	defer h.Shutdown()

	cohortName := "default"
	poolName := "dev-default"

	_, _ = htest.MustPOST[any](h.Echo, fmt.Sprintf("/api/v1/resource-cohorts/%s/resourcepools", cohortName), htest.WithJSON(reqM.ResourceCohortAddPoolRequest{Name: poolName}))
	_, cohort := htest.GET[model.ResourceCohort](h.Echo, "/api/v1/resource-cohorts/"+cohortName)
	for _, p := range cohort.Resourcepools {
		if p.Name == poolName {
			return
		}
	}
	assert.FailNow(t, "unexpected resourcepools %+v", cohort.Resourcepools)
}

func TestHTTPHandler_RemovePoolFromResourceCohort(t *testing.T) {
	h := setup(t)
	defer h.Shutdown()

	cohortName := "default"
	poolName := "ksyun-default"

	_, cohort := htest.MustGET[model.ResourceCohort](h.Echo, "/api/v1/resource-cohorts/"+cohortName)
	checkDefaultCohortPool(t, cohort.Resourcepools)
	_, _ = htest.MustDELETE[any](h.Echo, fmt.Sprintf("/api/v1/resource-cohorts/%s/resourcepools/%s", cohortName, poolName))
	_, cohort = htest.MustGET[model.ResourceCohort](h.Echo, "/api/v1/resource-cohorts/"+cohortName)
	for _, pool := range cohort.Resourcepools {
		assert.NotEqual(t, poolName, pool.Name)
	}
}
