package api

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

	"github.com/gin-gonic/gin"
	"github.com/onsi/gomega"
)

func Test_getOrgIDFromReferer(t *testing.T) {
	g := gomega.NewWithT(t)

	referer := ""
	v := getValueFromReferer(referer, kibanaTenantKey, func() url.Values {
		return make(map[string][]string)
	})
	g.Expect(v).To(gomega.Equal(""))

	referer = "http://localhost:9200"
	v = getValueFromReferer(referer, kibanaTenantKey, func() url.Values {
		return make(map[string][]string)
	})
	g.Expect(v).To(gomega.Equal(""))

	referer = fmt.Sprintf("http://localhost:9200?%s=111", kibanaTenantKey)
	v = getValueFromReferer(referer, kibanaTenantKey, func() url.Values {
		return make(map[string][]string)
	})
	g.Expect(v).To(gomega.Equal("111"))

	referer = "http://localhost:9200"
	v = getValueFromReferer(referer, kibanaTenantKey, func() url.Values {
		values := make(map[string][]string)
		values[kibanaTenantKey] = []string{"222"}

		return values
	})
	g.Expect(v).To(gomega.Equal("222"))
}

// https://github.com/gin-gonic/gin/blob/ce20f107f5dc498ec7489d7739541a25dcd48463/context_test.go#L1747-L1765
type testResponseRecorder struct {
	*httptest.ResponseRecorder
	closeChannel chan bool
}

func (r *testResponseRecorder) CloseNotify() <-chan bool {
	return r.closeChannel
}

func (r *testResponseRecorder) closeClient() {
	r.closeChannel <- true
}

func createTestResponseRecorder() *testResponseRecorder {
	return &testResponseRecorder{
		httptest.NewRecorder(),
		make(chan bool, 1),
	}
}

func TestGetLogQueryClusterIDFromRequest(t *testing.T) {
	g := gomega.NewWithT(t)
	gin.SetMode(gin.TestMode)

	c, _ := gin.CreateTestContext(httptest.NewRecorder())
	c.Request, _ = http.NewRequest(http.MethodGet, "http://localhost:8080/log/query/loki/api/v1/query?cluster_id=query-cluster", nil)
	c.Request.Header.Set("x-clinic-cluster-id", "header-cluster")
	c.Request.AddCookie(&http.Cookie{Name: GrafanaTiDBClusterCookie, Value: "cookie-cluster"})
	g.Expect(getLogQueryClusterIDFromRequest(c)).To(gomega.Equal("query-cluster"))

	c, _ = gin.CreateTestContext(httptest.NewRecorder())
	c.Request, _ = http.NewRequest(http.MethodGet, "http://localhost:8080/log/query/loki/api/v1/query?var-tidb_cluster=var-cluster", nil)
	c.Request.Header.Set(URLReferer, "http://localhost:3000/dash?var-cluster_id=referer-cluster")
	c.Request.AddCookie(&http.Cookie{Name: GrafanaTiDBClusterCookie, Value: "cookie-cluster"})
	g.Expect(getLogQueryClusterIDFromRequest(c)).To(gomega.Equal("var-cluster"))

	c, _ = gin.CreateTestContext(httptest.NewRecorder())
	c.Request, _ = http.NewRequest(http.MethodGet, "http://localhost:8080/log/query/loki/api/v1/query?var-cluster_id=request-cluster", nil)
	c.Request.Header.Set(URLReferer, "http://localhost:3000/dash?var-cluster_id=referer-cluster")
	c.Request.AddCookie(&http.Cookie{Name: GrafanaTiDBClusterCookie, Value: "cookie-cluster"})
	g.Expect(getLogQueryClusterIDFromRequest(c)).To(gomega.Equal("request-cluster"))

	c, _ = gin.CreateTestContext(httptest.NewRecorder())
	c.Request, _ = http.NewRequest(http.MethodGet, "http://localhost:8080/log/query/loki/api/v1/query", nil)
	c.Request.Header.Set(URLReferer, "http://localhost:3000/dash?var-cluster_id=referer-cluster")
	c.Request.AddCookie(&http.Cookie{Name: GrafanaTiDBClusterCookie, Value: "cookie-cluster"})
	g.Expect(getLogQueryClusterIDFromRequest(c)).To(gomega.Equal("referer-cluster"))

	c, _ = gin.CreateTestContext(httptest.NewRecorder())
	c.Request, _ = http.NewRequest(http.MethodGet, "http://localhost:8080/log/query/loki/api/v1/query", nil)
	c.Request.AddCookie(&http.Cookie{Name: GrafanaTiDBClusterCookie, Value: "cookie-cluster"})
	g.Expect(getLogQueryClusterIDFromRequest(c)).To(gomega.Equal("cookie-cluster"))
}

func TestGetGrafanaClusterIDFromRequest(t *testing.T) {
	g := gomega.NewWithT(t)
	gin.SetMode(gin.TestMode)

	c, _ := gin.CreateTestContext(httptest.NewRecorder())
	c.Request, _ = http.NewRequest(http.MethodGet, "http://localhost:8080/grafana/api/ds/query?var-cluster_id=query-cluster", nil)
	g.Expect(getGrafanaClusterIDFromRequest(c)).To(gomega.Equal("query-cluster"))

	c, _ = gin.CreateTestContext(httptest.NewRecorder())
	c.Request, _ = http.NewRequest(http.MethodGet, "http://localhost:8080/grafana/api/ds/query?var-cluster_id=query-cluster", nil)
	c.Request.Header.Set(URLReferer, "http://localhost:3000/explore?var-cluster_id=referer-cluster")
	g.Expect(getGrafanaClusterIDFromRequest(c)).To(gomega.Equal("referer-cluster"))

	c, _ = gin.CreateTestContext(httptest.NewRecorder())
	c.Request, _ = http.NewRequest(http.MethodGet, "http://localhost:8080/grafana/api/ds/query?var-cluster_id=query-cluster", nil)
	c.Request.Header.Set(URLReferer, "http://localhost:3000/explore?var-tidb_cluster=tidb-cluster&var-cluster_id=cluster-id")
	g.Expect(getGrafanaClusterIDFromRequest(c)).To(gomega.Equal("tidb-cluster"))
}

func TestGetLogQueryControlPlaneInfoFromRequest(t *testing.T) {
	g := gomega.NewWithT(t)
	gin.SetMode(gin.TestMode)

	c, _ := gin.CreateTestContext(httptest.NewRecorder())
	c.Request, _ = http.NewRequest(http.MethodGet, "http://localhost:8080/log/query/loki/api/v1/query?var-control_plane_info=request-cp", nil)
	c.Request.Header.Set(URLReferer, "http://localhost:3000/dash?var-control_plane_info=referer-cp")
	c.Request.AddCookie(&http.Cookie{Name: GrafanaControlPlaneInfoCookie, Value: "cookie-cp"})
	g.Expect(getLogQueryControlPlaneInfoFromRequest(c)).To(gomega.Equal("request-cp"))

	c, _ = gin.CreateTestContext(httptest.NewRecorder())
	c.Request, _ = http.NewRequest(http.MethodGet, "http://localhost:8080/log/query/loki/api/v1/query", nil)
	c.Request.Header.Set(URLReferer, "http://localhost:3000/dash?var-control_plane_info=referer-cp")
	c.Request.AddCookie(&http.Cookie{Name: GrafanaControlPlaneInfoCookie, Value: "cookie-cp"})
	g.Expect(getLogQueryControlPlaneInfoFromRequest(c)).To(gomega.Equal("referer-cp"))

	c, _ = gin.CreateTestContext(httptest.NewRecorder())
	c.Request, _ = http.NewRequest(http.MethodGet, "http://localhost:8080/log/query/loki/api/v1/query", nil)
	c.Request.AddCookie(&http.Cookie{Name: GrafanaControlPlaneInfoCookie, Value: "cookie-cp"})
	g.Expect(getLogQueryControlPlaneInfoFromRequest(c)).To(gomega.Equal("cookie-cp"))
}

func TestTrimLogQueryRoutePrefix(t *testing.T) {
	g := gomega.NewWithT(t)

	g.Expect(trimLogQueryRoutePrefix("/log/query/loki/api/v1/query_range")).To(gomega.Equal("/loki/api/v1/query_range"))
}
