// Package mesh helps us mesh the different services together
package mesh

import (
	"crypto/tls"
	"net/http"
	"net/url"
	"path"
	"strconv"
	"strings"

	"github.com/gin-gonic/gin"

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

const (
	userIDHeader = "X-USER-ID"
)

// AuthType of Dashboard
type AuthType int

// HandleRouteStripGin handles the route and strips it as a prefix. This is useful for proxying.
func HandleRouteStripGin(eng *gin.Engine, route string, handler http.Handler) {
	eng.Any(path.Join(route, "*any"), gin.WrapH(http.StripPrefix(route, handler)))
}

func isMetricsPath(urlPath string) bool {
	paths := strings.Split(path.Clean(urlPath), "/")
	if len(paths) < 3 {
		return false
	}

	if paths[2] == "prometheus" {
		return true
	}

	return false
}

func isDashboardPath(urlPath string) bool {
	paths := strings.Split(path.Clean(urlPath), "/")
	if len(paths) < 4 {
		return false
	}

	if paths[2] == "pd" && paths[3] == "dashboard" {
		return true
	}

	return false
}

func isK8sDashboardPath(urlPath string) bool {
	paths := strings.Split(path.Clean(urlPath), "/")
	if len(paths) < 3 {
		return false
	}

	if paths[2] == "kubernetes_dashboard" {
		return true
	}

	return false
}

func parseClusterIDFromProxyURL(urlPath string) (uint64, error) {
	// TODO: better way to find clusterID
	paths := strings.Split(path.Clean(urlPath), "/")
	if len(paths) < 2 {
		return 0, errors.New("invalid proxy url")
	}
	clusterID := paths[1]
	clusterIDParsed, err := strconv.ParseUint(clusterID, 10, 64)
	if err != nil {
		return 0, errors.Annotate(err, "invalid proxy url")
	}
	return clusterIDParsed, nil
}

func pingcapEmail(email string) bool {
	parts := strings.Split(email, "@")
	return len(parts) > 1 && parts[1] == "pingcap.com"
}

func getByBaseURL(req *http.Request, baseURL string) (*tls.Config, *url.URL, error) {
	if !strings.HasPrefix(baseURL, "http://") && !strings.HasPrefix(baseURL, "https://") {
		baseURL = "https://" + baseURL
	}

	paths := strings.Split(req.URL.Path, "/")
	if len(paths) < 2 {
		return nil, nil, errors.Errorf("invalid proxy url path %q", req.URL.Path)
	}

	u, err := url.Parse(baseURL)
	if err != nil {
		return nil, nil, errors.Annotatef(err, "failed to parse base url: %s", baseURL)
	}

	if len(paths) >= 3 && paths[2] == "prometheus" {
		req.URL.Path = strings.Join(append([]string{u.Path}, paths[3:]...), "/")
	} else {
		req.URL.Path = strings.Join(append([]string{u.Path}, paths[2:]...), "/")
	}
	log.Debug("connecting to endpoint", zap.String("endpoint", u.Host), zap.String("path", req.URL.Path))

	target := u.Scheme + "://" + u.Host + "?" + u.Query().Encode()
	parsedURL, err := url.Parse(target)
	return nil, parsedURL, err
}
