package topsql

import (
	"net/http/httptest"
	"testing"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/stretchr/testify/require"
)

func TestBindHeaderLowerCase(t *testing.T) {
	gin.SetMode(gin.TestMode)
	req := httptest.NewRequest("GET", "/", nil)
	req.Header.Set("x-provider", "aws")
	req.Header.Set("x-region", "us-east-1")
	req.Header.Set("x-org-id", "1")
	req.Header.Set("x-project-id", "2")
	req.Header.Set("x-cluster-id", "3")

	c := gin.Context{Request: req}
	var header ClusterHeader
	err := c.BindHeader(&header)
	require.NoError(t, err)
	err = header.Validate()
	require.NoError(t, err)

	require.Equal(t, "aws", *header.Provider)
	require.Equal(t, "us-east-1", *header.Region)
	require.Equal(t, uint64(1), *header.TenantID)
	require.Equal(t, uint64(2), *header.ProjectID)
	require.Equal(t, uint64(3), *header.ClusterID)
}

func TestBindHeaderUpperCase(t *testing.T) {
	gin.SetMode(gin.TestMode)
	record := httptest.NewRecorder()
	c, _ := gin.CreateTestContext(record)

	req := httptest.NewRequest("GET", "/", nil)
	req.Header.Set("X-Provider", "aws")
	req.Header.Set("X-Region", "us-east-1")
	req.Header.Set("X-Org-Id", "1")
	req.Header.Set("X-Project-Id", "2")
	req.Header.Set("X-Cluster-Id", "3")
	c.Request = req

	var header ClusterHeader
	err := c.BindHeader(&header)
	require.NoError(t, err)
	err = header.Validate()
	require.NoError(t, err)

	require.Equal(t, "aws", *header.Provider)
	require.Equal(t, "us-east-1", *header.Region)
	require.Equal(t, uint64(1), *header.TenantID)
	require.Equal(t, uint64(2), *header.ProjectID)
	require.Equal(t, uint64(3), *header.ClusterID)
}

func TestHeaderMissingField(t *testing.T) {
	gin.SetMode(gin.TestMode)
	record := httptest.NewRecorder()
	c, _ := gin.CreateTestContext(record)

	req := httptest.NewRequest("GET", "/", nil)
	req.Header.Set("x-provider", "aws")
	req.Header.Set("x-region", "us-east-1")
	req.Header.Set("x-org-id", "1")
	req.Header.Set("x-project-id", "2")
	c.Request = req

	var header ClusterHeader
	err := c.BindHeader(&header)
	require.NoError(t, err)
	err = header.Validate()
	require.EqualError(t, err, "cluster id not found")
}

func TestHeaderInvalidField(t *testing.T) {
	gin.SetMode(gin.TestMode)
	record := httptest.NewRecorder()
	c, _ := gin.CreateTestContext(record)

	req := httptest.NewRequest("GET", "/", nil)
	req.Header.Set("x-provider", "aws")
	req.Header.Set("x-region", "us-east-1")
	req.Header.Set("x-org-id", "1")
	req.Header.Set("x-project-id", "2")
	req.Header.Set("x-cluster-id", "wrong")
	c.Request = req

	var header ClusterHeader
	err := c.BindHeader(&header)
	require.EqualError(t, err, "strconv.ParseUint: parsing \"wrong\": invalid syntax")
}

func TestInstanceQuery(t *testing.T) {
	gin.SetMode(gin.TestMode)
	record := httptest.NewRecorder()
	c, _ := gin.CreateTestContext(record)

	req := httptest.NewRequest("GET", "/?start=1&end=2", nil)
	c.Request = req

	var query InstanceQuery
	err := c.BindQuery(&query)
	require.NoError(t, err)
	err = query.Validate()
	require.NoError(t, err)

	require.Equal(t, float64(1), *query.StartSecs)
	require.Equal(t, float64(2), *query.EndSecs)
}

func TestInstanceQueryMissingField(t *testing.T) {
	gin.SetMode(gin.TestMode)
	record := httptest.NewRecorder()
	c, _ := gin.CreateTestContext(record)

	req := httptest.NewRequest("GET", "/?start=1", nil)
	c.Request = req

	var query InstanceQuery
	err := c.BindQuery(&query)
	require.NoError(t, err)
	err = query.Validate()
	require.EqualError(t, err, "end not found")
}

func TestInstanceQueryInvalidField(t *testing.T) {
	gin.SetMode(gin.TestMode)
	record := httptest.NewRecorder()
	c, _ := gin.CreateTestContext(record)

	req := httptest.NewRequest("GET", "/?start=1&end=wrong", nil)
	c.Request = req

	var query InstanceQuery
	err := c.BindQuery(&query)
	require.EqualError(t, err, "strconv.ParseFloat: parsing \"wrong\": invalid syntax")
}

func TestSummaryQuery(t *testing.T) {
	gin.SetMode(gin.TestMode)
	record := httptest.NewRecorder()
	c, _ := gin.CreateTestContext(record)

	req := httptest.NewRequest("GET", "/?start=1&end=2&window=10m&top=5&instance=tidb-0&instance_type=tidb", nil)
	c.Request = req

	var query SummaryQuery
	err := c.BindQuery(&query)
	require.NoError(t, err)
	err = query.Validate()
	require.NoError(t, err)

	require.Equal(t, float64(1), *query.StartSecs)
	require.Equal(t, float64(2), *query.EndSecs)
	require.Equal(t, 10*time.Minute, *query.Window)
	require.Equal(t, 5, *query.Top)
	require.Equal(t, "tidb-0", *query.Instance)
	require.Equal(t, "tidb", *query.InstanceType)
}

func TestSummaryQueryMissingField(t *testing.T) {
	gin.SetMode(gin.TestMode)
	record := httptest.NewRecorder()
	c, _ := gin.CreateTestContext(record)

	req := httptest.NewRequest("GET", "/?start=1&end=2&window=10m&top=5&instance_type=tidb", nil)
	c.Request = req

	var query SummaryQuery
	err := c.BindQuery(&query)
	require.NoError(t, err)
	err = query.Validate()
	require.EqualError(t, err, "instance not found")
}

func TestSummaryQueryInvalidField(t *testing.T) {
	gin.SetMode(gin.TestMode)
	record := httptest.NewRecorder()
	c, _ := gin.CreateTestContext(record)

	req := httptest.NewRequest("GET", "/?start=1&end=2&window=wrong&top=5&instance=tidb-0&instance_type=tidb", nil)
	c.Request = req

	var query SummaryQuery
	err := c.BindQuery(&query)
	require.EqualError(t, err, "time: invalid duration \"wrong\"")
}
