package utils

import (
	"bytes"
	"fmt"
	"net/url"
	"path/filepath"
	"strings"

	"github.com/BurntSushi/toml"
	"github.com/joho/godotenv"
	"github.com/pingcap/log"
	"github.com/pingcap/test-infra/sdk/core"
	"go.uber.org/zap"
)

var (
	logger         *zap.Logger
	ParamPrefix    string
	ResourcePrefix string
)

func init() {
	_, logger = GetCtxAndLogger()
	ResourcePrefix = "TI_PARAM_RES_"
	ParamPrefix = "TI_PARAM_STR_"
}

func GetCtxAndLogger() (ctx core.TestContext, logger *zap.Logger) {
	godotenv.Load()

	bc, err := core.BuildContext()
	if err != nil {
		core.Fail(err.Error())
	}
	ctx = bc.(core.TestContext)
	logger = ctx.Logger()
	return ctx, logger
}

func Try(xs ...interface{}) interface{} {
	if len(xs) == 0 {
		return nil
	}
	if err, ok := xs[len(xs)-1].(error); ok && err != nil {
		core.Fail(err.Error())
	}
	return xs[0]
}

func RenamePath(path *string, uniq string) error {
	u, err := url.Parse(*path)
	if err != nil {
		return err
	}
	u.Path = u.Path + uniq
	*path = u.String()
	return nil
}

func DiffStringSlices(more, less []string) []string {
	res := make([]string, 0)
	for _, m := range more {
		for i, l := range less {
			if m == l {
				break
			}
			if i == len(less)-1 {
				res = append(res, m)
			}
		}
	}
	return res
}

func CompareStringSlice(more, less []string, extra ...*string) bool {
	res := DiffStringSlices(more, less)
	if len(res) != len(extra) {
		return false
	}
	for _, r := range res {
		for i, e := range extra {
			if r == *e {
				break
			}
			if i == len(res)-1 {
				return false
			}
		}
	}
	return true
}

func ExtractValues(s, begin, end string) string {
	idx_begin := strings.Index(s, begin)
	idx_end_off := strings.Index(s[idx_begin:], end)
	return s[idx_begin+len(begin) : idx_begin+idx_end_off]
}

func BackQuote(s string) string {
	return "`" + s + "`"
}

func CheckResult(stdout string, needCheck string, times int) bool {
	return times == strings.Count(stdout, needCheck)
}

func CheckResultTrue(stdout string, times int) bool {
	return CheckResult(stdout, "\"result\": true", times)
}

func CheckResultFalse(stdout string, times int) bool {
	return CheckResult(stdout, "\"result\": false", times)
}

func TempPath(path string) string {
	return filepath.Join("tmp", path)
}

func MergeToml(tomlStrs ...string) (string, error) {
	var output = make(map[string]map[string]interface{})
	for _, tomlStr := range tomlStrs {
		log.Info(fmt.Sprintf("merging toml string: %s", tomlStr))
		var tmp map[string]map[string]interface{}
		_, err := toml.Decode(tomlStr, &tmp)
		if err != nil {
			return "", err
		}

		for k, v := range tmp {
			if _, ok := output[k]; ok {
				log.Info(fmt.Sprintf("level 1 key: %s exists", k))
				for k2, v2 := range v {
					if _, ok := output[k][k2]; ok {
						log.Warn(fmt.Sprintf("level 2 key: %s, value: %v already exists, replace it with %s", k2, output[k][k2], v2))
						output[k][k2] = v2
					} else {
						output[k][k2] = v2
					}
				}
			} else {
				output[k] = v
			}
		}
	}
	buff := new(bytes.Buffer)
	encoder := toml.NewEncoder(buff)
	err := encoder.Encode(output)
	if err != nil {
		fmt.Println("encoder failed")
	}
	return buff.String(), nil
}
