package web

import (
	"encoding/base64"
	"strings"

	"github.com/intel-go/fastjson"
	"github.com/valyala/fasthttp"
	proxy "github.com/yeqown/fasthttp-reverse-proxy"
	"go.uber.org/zap"

	"tiup-log-collector/log"
)

var (
	dashboardAPIPrefix  = "/api/v1/dashboard/report"
	dashboardTrackAPI   = dashboardAPIPrefix + "/track"
	mixpanelAPIHost     = "api-js.mixpanel.com"
	mixpanelProxyServer = proxy.NewReverseProxy(mixpanelAPIHost)
)

func dashboardHandler(ctx *fasthttp.RequestCtx) {
	defer recoverError("dashboardRequest", ctx)

	logDashboardTrack(ctx)
	proxyDashboardRequest(ctx)
}

func logDashboardTrack(ctx *fasthttp.RequestCtx) {
	if !strings.HasPrefix(string(ctx.Path()), dashboardTrackAPI) {
		// only save logs for '/track'
		return
	}

	logItem := func(item interface{}) {
		log.E().Info(
			"dashboard",
			zap.String("app", "dashboard"),
			zap.String("ip", ClientIP(ctx)),
			zap.String("userAgent", string(ctx.UserAgent())),
			zap.Any("content", item),
		)
	}

	dataEnc := ctx.FormValue("data")
	if len(dataEnc) == 0 {
		return
	}

	dataDec, err := base64.StdEncoding.DecodeString(string(dataEnc))
	if err != nil {
		return
	}

	var dataJSON interface{}
	err = fastjson.Unmarshal(dataDec, &dataJSON)
	if err != nil {
		return
	}

	// check json is a slice or a map
	// if it is a slice, we need to handle it item by item
	// slice: []interface{}
	// map: map[string]interface{}
	if arr, ok := dataJSON.([]interface{}); ok {
		for _, v := range arr {
			logItem(v)
		}
	} else {
		logItem(dataJSON)
	}
}

func proxyDashboardRequest(ctx *fasthttp.RequestCtx) {
	path := string(ctx.Path())
	newPath := strings.NewReplacer(dashboardAPIPrefix, "").Replace(path)
	ctx.URI().SetPath(newPath)
	// ctx.URI().SetScheme("https") // unnecessary
	ctx.URI().SetHost(mixpanelAPIHost) // very important!
	mixpanelProxyServer.ServeHTTP(ctx)
}
