package util

import (
	"context"
	"crypto/md5"
	"dataapps/commons/config"
	"dataapps/commons/contextvar"
	"dataapps/commons/grpc"
	"encoding/hex"
	"sort"
	"strconv"
	"strings"
	"time"

	"github.com/tidbcloud/tiinf/monitor/tilog"
	"go.uber.org/zap"

	"go.opentelemetry.io/otel/trace"
)

func ArrayIn(target string, strArray []string) bool {
	target = strings.ToLower(target)
	strArray = ToLower(strArray)
	sort.Strings(strArray)
	index := sort.SearchStrings(strArray, target)
	if index < len(strArray) && strArray[index] == target {
		return true
	}
	return false
}

func ToLower(strArray []string) []string {
	result := make([]string, 0, len(strArray))
	for _, str := range strArray {
		result = append(result, strings.ToLower(str))
	}
	return result
}

func KeySet(m map[string]interface{}) []string {
	j := 0
	keys := make([]string, len(m))
	for k := range m {
		keys[j] = k
		j++
	}
	return keys
}

func TraceContext(ctx context.Context) context.Context {
	return trace.ContextWithSpan(context.Background(), trace.SpanFromContext(ctx))
}

func NewContext(ctx context.Context) context.Context {
	newctx := context.TODO()

	span := trace.SpanFromContext(ctx)
	newctx = trace.ContextWithSpan(newctx, span)

	logger := contextvar.Logger(ctx)
	newctx = contextvar.WithLogger(newctx, logger)

	return newctx
}

func GetTraceId(ctx context.Context) string {
	traceId := trace.SpanFromContext(ctx).SpanContext().TraceID()
	return traceId.String()
}

func GenerateRegionLokiLink(ctx context.Context, clusterId uint64) string {
	// current time (-10min,+10min)
	currentTime := time.Now()
	l, _ := time.ParseDuration("-10m")
	r, _ := time.ParseDuration("+10m")
	lstr := currentTime.Add(l)
	lunix := lstr.Unix() * 1000
	lunixstr := strconv.FormatInt(lunix, 10)
	rstr := currentTime.Add(r)
	runix := rstr.Unix() * 1000
	runixstr := strconv.FormatInt(runix, 10)

	env := config.Global().GardenerConfig.Env
	region := "us-west-2"
	if env == "prod" {
		clusterInfo, err := grpc.GetClusterByIds(ctx, []uint64{clusterId})
		if err != nil {
			tilog.Error(ctx, "GenerateRegionLokiLink-get cluster info failed", zap.Any("error", err))
			return "https://self-monitoring-grafana.observability.tidbcloud.com/explore?orgId=1&left=%7B%22datasource%22:%22Loki-regional-" + region + "%22,%22queries%22:%5B%7B%22refId%22:%22A%22,%22editorMode%22:%22builder%22,%22expr%22:%22%7Bcluster%3D%5C%22o11y-control-plane%5C%22,%20container%3D~%5C%22dataservice-dataapp-gateway%7Cdataservice-dataapp-executor%5C%22%7D%20%7C%3D%20%60" + GetTraceId(ctx) + "%60%22,%22queryType%22:%22range%22%7D%5D,%22range%22:%7B%22from%22:%22" + lunixstr + "%22,%22to%22:%22" + runixstr + "%22%7D%7D"
		}
		region = clusterInfo[clusterId].RegionName
		return "https://self-monitoring-grafana.observability.tidbcloud.com/explore?orgId=1&left=%7B%22datasource%22:%22Loki-regional-" + region + "%22,%22queries%22:%5B%7B%22refId%22:%22A%22,%22editorMode%22:%22builder%22,%22expr%22:%22%7Bcluster%3D%5C%22o11y-control-plane%5C%22,%20container%3D~%5C%22dataservice-dataapp-gateway%7Cdataservice-dataapp-executor%5C%22%7D%20%7C%3D%20%60" + GetTraceId(ctx) + "%60%22,%22queryType%22:%22range%22%7D%5D,%22range%22:%7B%22from%22:%22" + lunixstr + "%22,%22to%22:%22" + runixstr + "%22%7D%7D"
	} else {
		return "https://self-monitoring-grafana.observability-" + env + ".pingcap.cloud/explore?orgId=1&left=%7B%22datasource%22:%22Loki-regional-" + region + "%22,%22queries%22:%5B%7B%22refId%22:%22A%22,%22editorMode%22:%22builder%22,%22expr%22:%22%7Bcluster%3D%5C%22o11y-control-plane%5C%22,%20container%3D~%5C%22dataservice-dataapp-gateway%7Cdataservice-dataapp-executor%5C%22%7D%20%7C%3D%20%60" + GetTraceId(ctx) + "%60%22,%22queryType%22:%22range%22%7D%5D,%22range%22:%7B%22from%22:%22" + lunixstr + "%22,%22to%22:%22" + runixstr + "%22%7D%7D"
	}
}

func Md5(content string) string {
	has := md5.New()
	has.Write([]byte(content))
	b := has.Sum(nil)
	return hex.EncodeToString(b)
}
