package nodescorer

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

	"github.com/go-logr/logr"
	. "github.com/onsi/gomega"
	"github.com/pingcap/errors"
	"github.com/tidbcloud/aws-shared-provider/pkg/utils/query"
	"sigs.k8s.io/controller-runtime/pkg/log"
)

func TestNodeScorer_getCpuIdle(t *testing.T) {
	errorData := `{"status":"error","errorType":"bad_data","error":"invalid parameter 'query': parse error"}`
	emptyData := `{"status":"success","data":{"resultType":"matrix","result":[]}}`
	hasData := `{"status":"success","data":{"resultType":"matrix","result":[` +
		`{"metric":{"instance":"node1"},"values":[[1667460382,"0.91"]]},` +
		`{"metric":{"instance":"node2"},"values":[[1667460382,"0.92"]]},` +
		`{"metric":{"instance":"node3"},"values":[[1667460382,"0.93"]]}]}}`
	tidbPoolReadyNodes := map[string]bool{
		"node1": true,
		"node2": true,
	}

	tests := []struct {
		name        string
		retData     string
		expectedErr error
		expectedRes map[string]float32
	}{
		{
			name:        "get error",
			retData:     errorData,
			expectedErr: errors.Errorf(`query range failed: "invalid parameter 'query': parse error"`),
		}, {
			name:        "get empty res",
			retData:     emptyData,
			expectedRes: map[string]float32{},
		}, {
			name:    "get 2 res, filter out one",
			retData: hasData,
			expectedRes: map[string]float32{
				"node1": 0.91,
				"node2": 0.92,
			},
		},
	}

	var data string
	promServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintln(w, data)
	}))
	defer promServer.Close()
	querier := query.NewPromQueryer(nil, promServer.URL)

	ns := &NodeScorer{
		Logger:      logr.New(log.NullLogSink{}),
		ctx:         context.Background(),
		o11yQuerier: querier,
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			g := NewGomegaWithT(t)
			data = tt.retData
			res, err := ns.getCpuIdle(tidbPoolReadyNodes)
			if tt.expectedErr == nil {
				g.Expect(err).To(Succeed())
				g.Expect(res).To(Equal(tt.expectedRes))
			} else {
				g.Expect(err).To(MatchError(tt.expectedErr.Error()))
			}
		})
	}
}
