package http

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

	"github.com/gin-gonic/gin"
	"github.com/tidbcloud/devops/pkg/infra/utils/test"

	. "github.com/onsi/ginkgo/v2"
	. "github.com/onsi/gomega"
)

func TestHTTP(t *testing.T) {
	RegisterFailHandler(Fail)
	RunSpecs(t, "HTTP Suite", test.ReporterConfig())
}

var _ = Describe("[HTTP]", func() {
	Describe("Proxy", func() {
		It("uses Rewrite while preserving proxy request behavior", func() {
			gin.SetMode(gin.TestMode)

			var received *http.Request
			backend := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
				received = r.Clone(r.Context())
				w.WriteHeader(http.StatusNoContent)
			}))
			defer backend.Close()

			target, err := url.Parse(backend.URL)
			Expect(err).To(BeNil())

			router := gin.New()
			router.GET("/*path", func(c *gin.Context) {
				Proxy(c,
					[]RequestOpts{
						ReplaceScheme(target.Scheme),
						ReplaceHost(target.Host),
						AddQuery(map[string]string{"b": "2"}),
						SetHeader(map[string]string{"X-Test": "value"}),
					},
					[]ProxyOpts{
						func(proxy *httputil.ReverseProxy) {
							proxy.Transport = backend.Client().Transport
						},
					},
				)
			})

			proxyServer := httptest.NewServer(router)
			defer proxyServer.Close()

			req, err := http.NewRequest(http.MethodGet, proxyServer.URL+"/original?a=1", nil)
			Expect(err).To(BeNil())
			req.Header.Set("X-Forwarded-For", "1.1.1.1")
			req.Host = "client.example"
			resp, err := proxyServer.Client().Do(req)
			Expect(err).To(BeNil())
			defer resp.Body.Close()

			Expect(resp.StatusCode).To(Equal(http.StatusNoContent))
			Expect(received).NotTo(BeNil())
			Expect(received.Host).To(Equal(target.Host))
			Expect(received.URL.Path).To(Equal("/original"))
			Expect(received.URL.RawQuery).To(Equal("a=1&b=2"))
			Expect(received.Header.Get("X-Test")).To(Equal("value"))
			Expect(received.Header.Get("X-Forwarded-For")).To(HavePrefix("1.1.1.1, "))
			Expect(received.Header.Get("X-Forwarded-Host")).To(Equal("client.example"))
			Expect(received.Header.Get("X-Forwarded-Proto")).To(Equal("http"))
		})
	})
})
