package proxy

import (
	"fmt"
	"net/http"
	"net/http/httputil"
	"net/url"
	"strings"

	"github.com/pingcap/log"
	"go.uber.org/zap"
)

const proxyPrefix = "/proxy/"

type proxyRoute struct {
	name    string
	handler http.Handler
}

var proxyRoutes []proxyRoute

func registerProxyRoute(r proxyRoute) {
	proxyRoutes = append(proxyRoutes, r)
}

func Handler() http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		path := req.URL.Path
		path = strings.TrimPrefix(path, proxyPrefix)
		items := strings.Split(path, "/")
		if len(items) < 1 {
			log.L().Warn("invalid proxy path", zap.String("path", req.URL.Path))
			http.Error(w, fmt.Sprintf("invalid proxy path: %s", req.URL.Path), http.StatusBadRequest)
			return
		}
		for _, route := range proxyRoutes {
			if items[0] == route.name {
				req.URL.Path = strings.Join(items[1:], "/")
				route.handler.ServeHTTP(w, req)
				break
			}
		}
	})
}

func GetReverseProxy(addr string) *httputil.ReverseProxy {
	// input addr should include schema, like : http://xxx
	targetURL, _ := url.Parse(addr)
	proxy := httputil.NewSingleHostReverseProxy(targetURL)
	proxy.ErrorHandler = func(w http.ResponseWriter, r *http.Request, err error) {
		w.WriteHeader(http.StatusBadGateway)
		log.L().Error("proxying the request failed", zap.String("path", r.URL.Path), zap.Error(err))
	}
	return proxy
}
