package main

import (
	"context"
	"encoding/csv"
	"encoding/json"
	"fmt"
	"net/http"
	"os"
	"path/filepath"
	"reflect"
	"regexp"
	"strconv"
	"strings"
	"unicode"

	_ "github.com/go-sql-driver/mysql"
	"github.com/hashicorp/go-version"
	"github.com/jmoiron/sqlx"
	"github.com/spf13/cobra"
	pb "github.com/tidbcloud/config-center/proto/config_center"
	"google.golang.org/grpc"
	"google.golang.org/protobuf/types/known/structpb"
)

// clusterConfigCmd represents the cluster_config command
var paramDictCmd = &cobra.Command{
	Use:   "dict",
	Short: "config dict related operations",
	Long:  `config dict related operations`,
}

func init() {
	rootCmd.AddCommand(paramDictCmd)

	// clusterConfigCmd.AddCommand(newConfigAutoCreateCmd())
	paramDictCmd.AddCommand(migrateFromQADBCmd())
	paramDictCmd.AddCommand(listConfigDictCmd())
	paramDictCmd.AddCommand(copyConfigDictCmd())
	// paramDictCmd.AddCommand(updateConfigDictCmd())
	paramDictCmd.AddCommand(createConfigDictCmd())
	paramDictCmd.AddCommand(importDictFromDocCmd())
	paramDictCmd.AddCommand(importDictFromCodeCmd())
	paramDictCmd.AddCommand(diffDict())
	paramDictCmd.AddCommand(diffExistDict())
	paramDictCmd.AddCommand(purgeDictCmd())
}

type QAConfigDict struct {
	ItemName     string `db:"item_name"`
	ValueType    string `db:"value_type"`
	DefaultValue string `db:"default_value"`
	Version      string `db:"version"`
}

const BATCH_SIZE = 200

func migrateFromQADBCmd() *cobra.Command {
	var host, user, passwowrd, dbname string
	var port int64
	cmd := &cobra.Command{
		Use:   "migrateDict",
		Short: "migrate dict from QA",
		Long:  `migrate dict from QA`,
		RunE: func(cmd *cobra.Command, args []string) error {
			var opts []grpc.DialOption
			opts = append(opts, grpc.WithInsecure())
			conn, err := grpc.Dial(configCenterEndpoint, opts...)
			if err != nil {
				panic(err)
			}
			defer conn.Close()
			client := pb.NewConfigCenterServiceClient(conn)

			db, err := sqlx.Open("mysql", fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4", user, passwowrd, host, port, dbname))
			if err != nil {
				panic(err)
			}

			mapTableComponent := make(map[string]string)
			mapTableComponent["tbl_pd"] = "pd"
			mapTableComponent["tbl_tidb"] = "tidb"
			mapTableComponent["tbl_tiflash"] = "tiflash"
			mapTableComponent["tbl_tikv"] = "tikv"

			for k, v := range mapTableComponent {
				originConfigDict := []*QAConfigDict{}
				sql := fmt.Sprintf("select * from %s", k)
				err = db.Select(&originConfigDict, sql)
				if err != nil {
					fmt.Println("error is", err)
					return err
				}
				for i := 0; i < len(originConfigDict); i = i + BATCH_SIZE {
					items := make([]*pb.ConfigurationDictItem, 0)
					var maxIdx int
					if i+BATCH_SIZE < len(originConfigDict) {
						maxIdx = i + BATCH_SIZE
					} else {
						maxIdx = len(originConfigDict)
					}
					for j := i; j < maxIdx; j++ {
						vOrigin := originConfigDict[j]
						trimType := strings.Trim(vOrigin.ValueType, "'")
						var pbValue *structpb.Value
						var paramType pb.ConfigParamType
						switch trimType {
						case "bool":
							paramType = pb.ConfigParamType_bool
							if vOrigin.DefaultValue == "True" {
								pbValue, _ = structpb.NewValue(true)
							} else {
								pbValue, _ = structpb.NewValue(false)
							}
						case "int":
							paramType = pb.ConfigParamType_int
							num, err := strconv.Atoi(vOrigin.DefaultValue)
							if err != nil {
								continue
							}
							pbValue, _ = structpb.NewValue(num)
						case "float":
							paramType = pb.ConfigParamType_float
							f, err := strconv.ParseFloat(vOrigin.DefaultValue, 64)
							if err != nil {
								continue
							}
							pbValue, _ = structpb.NewValue(f)
						case "list":
							paramType = pb.ConfigParamType_json
							pbValue, _ = structpb.NewValue(vOrigin.DefaultValue)
						default:
							paramType = pb.ConfigParamType_string
							pbValue, _ = structpb.NewValue(vOrigin.DefaultValue)
						}

						reloadble := false
						items = append(items, &pb.ConfigurationDictItem{
							ConfigurationType: v,
							Version:           "v" + vOrigin.Version,
							ParamKey:          vOrigin.ItemName,
							DefaultValue:      pbValue,
							Type:              paramType,
							HotReloadable:     &reloadble,
						})
					}
					_, err = client.BatchCreateConfigurationDictItems(context.Background(), &pb.BatchCreateConfigurationDictRequest{ConfigurationDictItems: items})
					if err != nil {
						fmt.Println("fail to batch create", err)
					}
				}

			}
			return nil
		},
	}

	cmd.Flags().StringVarP(&host, "host", "H", "", "db host")
	cmd.Flags().StringVarP(&user, "user", "u", "", "db user")
	cmd.Flags().StringVarP(&passwowrd, "password", "p", "", "db password")
	cmd.Flags().Int64VarP(&port, "port", "P", 3306, "db port")
	cmd.Flags().StringVarP(&dbname, "database", "d", "", "db name")

	return cmd
}

func listConfigDictCmd() *cobra.Command {
	var clusterType, configType, version, keylike string
	var page, pageSize int64
	cmd := &cobra.Command{
		Use:   "list",
		Short: "list config dicts",
		Long:  `list config dicts`,
		RunE: func(cmd *cobra.Command, args []string) error {
			var opts []grpc.DialOption
			opts = append(opts, grpc.WithInsecure())
			conn, err := grpc.Dial(configCenterEndpoint, opts...)
			if err != nil {
				panic(err)
			}
			defer conn.Close()
			client := pb.NewConfigCenterServiceClient(conn)
			var typeParam *string
			if configType == `` {
				typeParam = nil
			} else {
				typeParam = &configType
			}
			resp, err := client.ListConfigurationDictItems(context.Background(), &pb.ListConfigurationDictItemsRequest{
				ClusterType:       pb.ClusterType(pb.ClusterType_value[clusterType]),
				ConfigurationType: typeParam,
				ParamKeyLike:      &keylike,
				Version:           &version,
				Page:              page,
				PageSize:          pageSize})

			if err != nil {
				fmt.Print("list dict items error", err)
				return err
			}
			fmt.Println("res list: ", resp.ConfigurationDictItems)
			fmt.Println("total len: ", resp.Total)
			fmt.Println("res len: ", len(resp.ConfigurationDictItems))
			return nil
		},
	}

	cmd.Flags().StringVarP(&clusterType, "cluster-type", "T", pb.ClusterType_DEDICATED_TIDB.String(), "cluster type")
	cmd.Flags().StringVar(&configType, "config-type", "", "config type")
	cmd.Flags().StringVarP(&version, "version", "v", "", "version")
	cmd.Flags().StringVarP(&keylike, "keyLike", "k", "", "key like")
	cmd.Flags().Int64VarP(&page, "page", "p", 1, "page")
	cmd.Flags().Int64VarP(&pageSize, "size", "s", 10, "page size")

	return cmd
}

func copyConfigDictCmd() *cobra.Command {
	var from, to string
	cmd := &cobra.Command{
		Use:   "copy",
		Short: "copy config dicts",
		Long:  `copy config dicts`,
		RunE: func(cmd *cobra.Command, args []string) error {
			var opts []grpc.DialOption
			opts = append(opts, grpc.WithInsecure())
			conn, err := grpc.Dial(configCenterEndpoint, opts...)
			if err != nil {
				panic(err)
			}
			defer conn.Close()
			client := pb.NewConfigCenterServiceClient(conn)

			_, err = client.CopyConfigurationDictFromOldVersion(context.Background(),
				&pb.CopyConfigurationDictFromOldVersionRequest{
					FromVersion: from,
					ToVersion:   to,
				})

			if err != nil {
				fmt.Print("copy from version error", err)
				return err
			}
			return nil
		},
	}

	cmd.Flags().StringVarP(&from, "from", "f", "", "from version")
	cmd.Flags().StringVarP(&to, "to", "t", "", "to verstion")

	return cmd
}

// func updateConfigDictCmd() *cobra.Command {
// 	var filename, version, paramKey string
// 	var defaultValFlag string
// 	// var defaultVal *string
// 	var hotReloadableFlag bool
// 	var hotReloadable *bool
// 	cmd := &cobra.Command{
// 		Use:   "update",
// 		Short: "update config dicts",
// 		Long:  `update config dicts`,
// 		RunE: func(cmd *cobra.Command, args []string) error {
// 			var opts []grpc.DialOption
// 			opts = append(opts, grpc.WithInsecure())
// 			conn, err := grpc.Dial(configCenterEndpoint, opts...)
// 			if err != nil {
// 				panic(err)
// 			}
// 			defer conn.Close()
// 			client := pb.NewConfigCenterServiceClient(conn)
// 			v, _ := structpb.NewValue()
// 			i, err := client.UpdateConfigurationDictItem(context.Background(),
// 				&pb.UpdateConfigurationDictItemReq{
// 					Version:       version,
// 					Filename:      filename,
// 					ParamKey:      paramKey,
// 					DefaultValue:  v,
// 					HotReloadable: hotReloadable,
// 				})

// 			if err != nil {
// 				fmt.Print("update error", err)
// 				return err
// 			}
// 			fmt.Println("item after updated", i)
// 			return nil
// 		},
// 	}

// 	cmd.Flags().StringVarP(&filename, "filename", "f", "", "filename")
// 	cmd.Flags().StringVarP(&version, "version", "v", "", "version")
// 	cmd.Flags().StringVarP(&paramKey, "paramKey", "p", "", "param key")
// 	cmd.Flags().StringVarP(&defaultValFlag, "default", "d", "", "default value")
// 	cmd.Flags().BoolVarP(&hotReloadableFlag, "hotReloadable", "r", false, "hotReloadable")
// 	if cmd.Flags().Changed("hotReloadable") {
// 		hotReloadable = &hotReloadableFlag
// 	}

// 	return cmd
// }

func createConfigDictCmd() *cobra.Command {
	var configType, version, paramKey, inputType, defaultVal string
	var hotReloadable bool
	cmd := &cobra.Command{
		Use:   "create",
		Short: "create config dicts",
		Long:  `create config dicts`,
		RunE: func(cmd *cobra.Command, args []string) error {
			var opts []grpc.DialOption
			opts = append(opts, grpc.WithInsecure())
			conn, err := grpc.Dial(configCenterEndpoint, opts...)
			if err != nil {
				panic(err)
			}
			defer conn.Close()
			client := pb.NewConfigCenterServiceClient(conn)
			items := make([]*pb.ConfigurationDictItem, 0)
			var pbValue *structpb.Value
			var paramType pb.ConfigParamType
			switch inputType {
			case "bool":
				paramType = pb.ConfigParamType_bool
				if defaultVal == "true" {
					pbValue, _ = structpb.NewValue(true)
				} else {
					pbValue, _ = structpb.NewValue(false)
				}
			case "int":
				paramType = pb.ConfigParamType_int
				num, err := strconv.Atoi(defaultVal)
				if err != nil {
					return err
				}
				pbValue, _ = structpb.NewValue(num)
			case "float":
				paramType = pb.ConfigParamType_float
				f, err := strconv.ParseFloat(defaultVal, 64)
				if err != nil {
					return err
				}
				pbValue, _ = structpb.NewValue(f)
			case "list":
				paramType = pb.ConfigParamType_json
				pbValue, _ = structpb.NewValue(defaultVal)
			default:
				paramType = pb.ConfigParamType_string
				pbValue, _ = structpb.NewValue(defaultVal)
			}
			items = append(items, &pb.ConfigurationDictItem{
				ConfigurationType: configType,
				Version:           version,
				ParamKey:          paramKey,
				Type:              paramType,
				DefaultValue:      pbValue,
				HotReloadable:     &hotReloadable,
			})
			i, err := client.BatchCreateConfigurationDictItems(context.Background(), &pb.BatchCreateConfigurationDictRequest{ConfigurationDictItems: items})

			if err != nil {
				fmt.Print("update error", err)
				return err
			}
			fmt.Println("item after updated", i)
			return nil
		},
	}

	cmd.Flags().StringVar(&configType, "config-type", "", "config type")
	cmd.Flags().StringVarP(&version, "version", "v", "", "version")
	cmd.Flags().StringVarP(&paramKey, "paramKey", "p", "", "param key")
	cmd.Flags().StringVarP(&defaultVal, "default", "d", "", "default value")
	cmd.Flags().BoolVarP(&hotReloadable, "hotReloadable", "r", false, "hotReloadable")
	cmd.Flags().StringVarP(&inputType, "type", "t", "string", "param type")

	return cmd
}

func importDictFromDocCmd() *cobra.Command {
	var configType, docPath string
	var allowInsert bool
	cmd := &cobra.Command{
		Use:   "import",
		Short: "import configurations from docs, by a specific version",
		Long:  `import configurations from docs, by a specific version`,
		RunE: func(cmd *cobra.Command, args []string) error {
			var opts []grpc.DialOption
			opts = append(opts, grpc.WithInsecure())
			conn, err := grpc.Dial(configCenterEndpoint, opts...)
			if err != nil {
				return err
			}
			defer conn.Close()
			client := pb.NewConfigCenterServiceClient(conn)

			return importDictFromDoc(client, docPath, configType, allowInsert)
		},
	}

	cmd.Flags().StringVar(&docPath, "path", "/gitops-data/docs", "local path of doc")
	cmd.Flags().StringVar(&configType, "config-type", "", "config type, e.g. tidb, tikv, pd, tiflash, leave empty to import all")
	cmd.Flags().BoolVar(&allowInsert, "allow-insert", false, "allow insert new items. Only update existing items by default")
	return cmd
}

func importDictFromCodeCmd() *cobra.Command {
	type Param struct {
		Key           string `json:"key"`
		Type          string `json:"type"`
		DefaultValue  any    `json:"default_value,omitempty"` // can be string, int, float, etc.
		Comment       string `json:"comment,omitempty"`
		HotReloadable *bool  `json:"hot_reloadable,omitempty"` // only present for some components (e.g. tiproxy)
	}

	var clusterType, version, configType, repo string
	cmd := &cobra.Command{
		Use:   "import2",
		Short: "import configurations from code, by a specific version",
		Long:  `import configurations from code, by a specific version`,
		RunE: func(cmd *cobra.Command, args []string) error {
			var opts []grpc.DialOption
			opts = append(opts, grpc.WithInsecure())
			conn, err := grpc.Dial(configCenterEndpoint, opts...)
			if err != nil {
				return err
			}
			defer conn.Close()
			client := pb.NewConfigCenterServiceClient(conn)

			newDict := []Param{}
			// read from local file
			configPath := fmt.Sprintf("%s/%s.json", version, configType)

			// tiflash learner and tikv config are almost the same
			if configType == "tiflash_learner" {
				// https://docs.pingcap.com/tidb/stable/tiflash-configuration/#configure-the-tiflash-learnertoml-file
				configPath = fmt.Sprintf("%s/tikv.json", version)
			}
			// nextgen: reuse tikv/tidb dict
			switch configType {
			case pb.SHARED_POOL_CONFIG_TIKV_WORKER,
				pb.SHARED_POOL_CONFIG_COPROCESSOR_WORKER:
				configPath = fmt.Sprintf("%s/tikv.json", version)
			case pb.SHARED_POOL_COMPONENT_TIDB_WORKER:
				configPath = fmt.Sprintf("%s/tidb.json", version)
			}

			localFilePath := filepath.Join(repo, configPath)
			fileData, err := os.ReadFile(localFilePath)
			if err != nil {
				return fmt.Errorf("failed to read local file %s: %w", localFilePath, err)
			}

			err = json.Unmarshal(fileData, &newDict)
			if err != nil {
				return fmt.Errorf("failed to parse JSON from %s: %w", localFilePath, err)
			}

			createDictReq := &pb.BatchCreateConfigurationDictRequest{
				ConfigurationDictItems: make([]*pb.ConfigurationDictItem, 0),
			}

			// compare with the dict from config center
			for _, item := range newDict {
				pbItem := &pb.ConfigurationDictItem{
					ClusterType:       pb.ClusterType(pb.ClusterType_value[clusterType]),
					ConfigurationType: configType,
					Version:           version,
					ParamKey:          item.Key,
					Type:              pb.ConfigParamType(pb.ConfigParamType_value[item.Type]),
					Description:       &item.Comment,
					HotReloadable:     item.HotReloadable,
					UpdatedBy:         "dict_dumper",
				}
				if item.DefaultValue != nil {
					pbItem.DefaultValue, err = pb.NewValue(item.DefaultValue)
					if err != nil {
						return fmt.Errorf("failed to convert default value for %s: %w", item.Key, err)
					}
				}
				createDictReq.ConfigurationDictItems = append(createDictReq.ConfigurationDictItems, pbItem)
			}
			if configType == "tiflash_learner" {
				createDictReq.ConfigurationDictItems = append(createDictReq.ConfigurationDictItems, &pb.ConfigurationDictItem{
					ClusterType:       pb.ClusterType(pb.ClusterType_value[clusterType]),
					ConfigurationType: configType,
					Version:           version,
					ParamKey:          "raftstore.snap-handle-pool-size",
					Type:              pb.ConfigParamType_int,
					DefaultValue:      structpb.NewNumberValue(2),
				})
			}

			_, err = client.BatchCreateConfigurationDictItems(context.Background(), createDictReq)

			return err
		},
	}

	cmd.Flags().StringVar(&clusterType, "cluster-type", "DEDICATED_TIDB", "cluster type")
	cmd.Flags().StringVar(&version, "version", "v8.5", "version")
	cmd.Flags().StringVar(&configType, "config-type", "tidb", "config type")
	cmd.Flags().StringVar(&repo, "path", "/dumped-dict", "local path to the config directory")
	return cmd
}

func diffDict() *cobra.Command {
	type Param struct {
		Key  string `json:"key"`
		Type string `json:"type"`
	}

	var version, configType string
	cmd := &cobra.Command{
		Use:   "diff",
		Short: "diff between exist dict and upstream code",
		Long:  `diff between exist dict and upstream code`,
		RunE: func(cmd *cobra.Command, args []string) error {
			var opts []grpc.DialOption
			opts = append(opts, grpc.WithInsecure())
			conn, err := grpc.Dial(configCenterEndpoint, opts...)
			if err != nil {
				return err
			}
			defer conn.Close()
			client := pb.NewConfigCenterServiceClient(conn)
			resp, err := client.ListConfigurationDictItems(context.Background(), &pb.ListConfigurationDictItemsRequest{
				ClusterType:       pb.ClusterType_DEDICATED_TIDB,
				ConfigurationType: &configType,
				Version:           &version,
			})
			if err != nil {
				return err
			}

			newDict := []Param{}
			// fetch from github kaaaaaaang/configdumper version branch pd.json
			raw, err := http.Get(fmt.Sprintf("https://raw.githubusercontent.com/kaaaaaaang/configdumper/refs/heads/main/versions/%s/%s.json", version, configType))
			if err != nil {
				return err
			}
			defer raw.Body.Close()
			if raw.StatusCode != http.StatusOK {
				return fmt.Errorf("failed to fetch data from GitHub: %s", raw.Status)
			}
			err = json.NewDecoder(raw.Body).Decode(&newDict)
			if err != nil {
				return err
			}
			// compare with the dict from config center
			for _, item := range newDict {
				found := false
				for _, old := range resp.GetConfigurationDictItems() {
					if item.Key == old.ParamKey {
						if item.Type != old.Type.String() {
							fmt.Printf("type not match! key: %s, old type: %s, new type: %s\n", item.Key, old.Type, item.Type)
						}
						found = true
						break
					}
				}
				if !found {
					fmt.Printf("not found! key: %s, type: %s\n", item.Key, item.Type)
				}
			}

			return nil
		},
	}

	cmd.Flags().StringVar(&version, "version", "v8.5", "version")
	cmd.Flags().StringVar(&configType, "config-type", "tidb", "config type")
	return cmd
}

func purgeDictCmd() *cobra.Command {
	var clusterType, configType, version string
	var force bool
	cmd := &cobra.Command{
		Use:   "purge",
		Short: "purge dict items by config type and version",
		Long:  `purge dict items by config type and version. Use --force to actually delete.`,
		RunE: func(cmd *cobra.Command, args []string) error {
			var opts []grpc.DialOption
			opts = append(opts, grpc.WithInsecure())
			conn, err := grpc.Dial(configCenterEndpoint, opts...)
			if err != nil {
				return err
			}
			defer conn.Close()
			client := pb.NewConfigCenterServiceClient(conn)

			req := &pb.PurgeDictItemsRequest{
				ClusterType: pb.ClusterType(pb.ClusterType_value[clusterType]),
				ConfigType:  configType,
				Force:       force,
			}
			if version != "" {
				req.Version = &version
			}

			resp, err := client.PurgeDictItems(context.Background(), req)
			if err != nil {
				return fmt.Errorf("failed to purge dict items: %w", err)
			}

			if force {
				fmt.Printf("Purged %d items\n", resp.PurgeCount)
			} else {
				fmt.Printf("Would purge %d items (use --force to actually delete)\n", resp.PurgeCount)
			}
			return nil
		},
	}

	cmd.Flags().StringVar(&clusterType, "cluster-type", "DEDICATED_TIDB", "cluster type")
	cmd.Flags().StringVar(&configType, "config-type", "", "config type (required)")
	cmd.Flags().StringVarP(&version, "version", "v", "", "version (optional, purge all versions if not specified)")
	cmd.Flags().BoolVar(&force, "force", false, "actually perform the purge")
	cmd.MarkFlagRequired("config-type")

	return cmd
}

func diffExistDict() *cobra.Command {
	var configType string
	cmd := &cobra.Command{
		Use:   "diff-exist <versionA> <versionB>",
		Short: "diff between different versions",
		Long:  `diff between different versions`,
		RunE: func(cmd *cobra.Command, args []string) error {
			if len(args) != 2 {
				return fmt.Errorf("please provide two versions to compare")
			}
			versionA := args[0]
			versionB := args[1]

			dictAindex := make(map[string]int)
			dictBindex := make(map[string]int)
			allParams := make(map[string]bool)

			var opts []grpc.DialOption
			opts = append(opts, grpc.WithInsecure())
			conn, err := grpc.Dial(configCenterEndpoint, opts...)
			if err != nil {
				return err
			}
			defer conn.Close()
			client := pb.NewConfigCenterServiceClient(conn)

			respA, err := client.ListConfigurationDictItems(context.Background(), &pb.ListConfigurationDictItemsRequest{
				ClusterType:       pb.ClusterType_DEDICATED_TIDB,
				ConfigurationType: &configType,
				Version:           &versionA,
			})
			if err != nil {
				return err
			}
			for i, item := range respA.GetConfigurationDictItems() {
				dictAindex[item.ParamKey] = i
				allParams[item.ParamKey] = true
			}

			respB, err := client.ListConfigurationDictItems(context.Background(), &pb.ListConfigurationDictItemsRequest{
				ClusterType:       pb.ClusterType_DEDICATED_TIDB,
				ConfigurationType: &configType,
				Version:           &versionB,
			})
			if err != nil {
				return err
			}
			for i, item := range respB.GetConfigurationDictItems() {
				dictBindex[item.ParamKey] = i
				allParams[item.ParamKey] = true
			}

			fmt.Printf("Comparing %s and %s for config type %s\n", versionA, versionB, configType)
			for param := range allParams {
				indexA, ok := dictAindex[param]
				if !ok {
					fmt.Printf("Only in %s: %s\n", versionB, param)
					continue
				}
				indexB, ok := dictBindex[param]
				if !ok {
					fmt.Printf("Only in %s: %s\n", versionA, param)
					continue
				}
				itemA := respA.GetConfigurationDictItems()[indexA]
				itemB := respB.GetConfigurationDictItems()[indexB]
				if itemA.Type != itemB.Type {
					fmt.Printf("Type mismatch for %s: %s in %s, %s in %s\n", param, itemA.Type, versionA, itemB.Type, versionB)
				}
			}

			return nil
		},
	}

	cmd.Flags().StringVar(&configType, "config-type", "tikv", "config type")
	return cmd
}

// func removeDuplicates(s []string) []string {
// 	set := make(map[string]bool)
// 	result := []string{}

// 	for _, item := range s {
// 		if _, ok := set[item]; !ok {
// 			set[item] = true
// 			result = append(result, item)
// 		}
// 	}

// 	return result
// }

func importDictFromDoc(client pb.ConfigCenterServiceClient, docPath string, configType string, allowInsert bool) error {
	componentFileMap := make(map[string]string)
	componentFileMap["tidb"] = "tidb-configuration-file.md"
	componentFileMap["tikv"] = "tikv-configuration-file.md"
	componentFileMap["pd"] = "pd-configuration-file.md"
	componentFileMap["tiflash"] = "tiflash-configuration-file.md"
	if configType != "" {
		// if configType is specified, only import the specified component
		componentFileMap = map[string]string{
			configType: componentFileMap[configType],
		}
	}

	// for a specific version.
	btVersion, err := os.ReadFile(filepath.Join(docPath, "version"))
	if err != nil {
		return err
	}
	version := string(btVersion)
	version = strings.TrimSuffix(version, "\n")
	// fmt.Println("version is ", version)

	// // delete exist configuration for the version
	// _, err = client.RemoveOneVersionDictItems(context.Background(), &pb.RemoveOneVersionDictItemsReq{Version: version})
	// if err != nil {
	// 	return err
	// }

	// dynamic map for tikv and pd
	dynamicMap, err := handleDynamic(docPath)
	if err != nil {
		return err
	}

	// import tidb, tikv, pd from doc.
	_, err = addConfigurationFromDoc(client, docPath, componentFileMap, version, dynamicMap, allowInsert)
	if err != nil {
		return err
	}

	return nil
}

func addConfigurationFromDoc(
	client pb.ConfigCenterServiceClient,
	docPath string,
	componentFileMap map[string]string,
	version string,
	dynamicMap map[string][]string,
	allowInsert bool,
) ([]*pb.ConfigurationDictItem, error) {
	// import configurations from doc
	items := make([]*pb.ConfigurationDictItem, 0)
	for component, fn := range componentFileMap {
		bt, err := os.ReadFile(filepath.Join(docPath, fn))
		if err != nil {
			return nil, err
		}
		var parsed map[string]map[string]PairedPbValue
		if component != "tiflash" {
			parsed = parseConfigurationFile(string(bt))
		} else {
			parsed = parseTiflashConfiguration(string(bt))
		}

		// delete
		delete(parsed, "quota.Background")
		delete(parsed, "quota.Foreground")

		for key, value := range parsed {
			if len(value) == 0 {
				continue
			}

			item := &pb.ConfigurationDictItem{
				ClusterType:       pb.ClusterType_DEDICATED_TIDB,
				ConfigurationType: component,
				Version:           version,
				ParamKey:          key,
			}

			// dynamic handle
			if paramList, exist := dynamicMap[component]; exist {
				for _, v := range paramList {
					if v == key {
						b := true
						item.HotReloadable = &b
					}
				}
			}

			// Description
			if attVal, exist := value["description"]; exist {
				tmps := attVal.Value.GetStringValue()
				item.Description = &tmps
			}

			if value["Default value"].Value == nil {
				fmt.Printf("param %s with config type %s does not have default value\n", component, key)
				item.Type = pb.ConfigParamType_unknown
				items = append(items, item)
				continue
			}

			// validation handle
			validation := pb.DictValidation{}
			if attVal, exist := value["Default value"]; exist {
				item.Type = attVal.Type
				item.DefaultValue = attVal.Value
				if item.Type == pb.ConfigParamType_string {
					strVal := attVal.Value.GetStringValue()
					unit := extractUnit(strVal)
					if unit != "" {
						pattern := unit + "$"
						validation.Pattern = &pattern
					}
				}
			}

			// Maximum
			if attVal, exist := value["Maximum value"]; exist {
				if attVal.Type == pb.ConfigParamType_float || attVal.Type == pb.ConfigParamType_int {
					numVal := attVal.Value.GetNumberValue()
					validation.Maximum = &numVal
				}
			}

			// Minimum
			if attVal, exist := value["Minumum value"]; exist {
				if attVal.Type == pb.ConfigParamType_float || attVal.Type == pb.ConfigParamType_int {
					numVal := attVal.Value.GetNumberValue()
					validation.Minimum = &numVal
				}
			}

			validationBytes, _ := json.Marshal(validation)
			item.Validation = string(validationBytes)
			items = append(items, item)
		}
	}

	special := specialparam(version)
	for _, tmpI := range items {
		if specialVal, ok := special[tmpI.ParamKey]; ok {
			tmpI.Type = specialVal.Type
			tmpI.DefaultValue = specialVal.Value
		}
	}

	// writeDictToCSV("/Users/hu/config-center/config-center/gitops-data/docs/", items)

	// Update the existed ones.
	toInsert := make([]*pb.ConfigurationDictItem, 0)
	for _, item := range items {
		exist, _ := client.GetConfigurationDictItem(
			context.Background(),
			&pb.GetConfigurationDictItemRequest{
				Version:           item.Version,
				ConfigurationType: item.ConfigurationType,
				ParamKey:          item.ParamKey,
			})
		// if exist, update
		if exist != nil {
			req := &pb.UpdateConfigurationDictItemReq{
				ClusterType:       pb.ClusterType_DEDICATED_TIDB,
				ConfigurationType: item.ConfigurationType,
				Version:           item.Version,
				ParamKey:          item.ParamKey,
				HotReloadable:     item.HotReloadable,
				Description:       item.Description,
				UpdatedBy:         "web_doc",
			}
			if exist.Type == item.Type {
				req.DefaultValue = item.DefaultValue
				req.Validation = &item.Validation
			} else {
				fmt.Printf("ignore default value: %s param %s's type inconsistency --- doc: %s, exist: %s\n", item.ConfigurationType, item.ParamKey, item.Type, exist.Type)
			}

			_, err := client.UpdateConfigurationDictItem(context.Background(), req)
			if err != nil {
				return nil, fmt.Errorf("fail to update %s param '%s' with error: %v", item.ConfigurationType, item.ParamKey, err)
			}
		} else {
			fmt.Printf("not exist: %s param '%s'\n", item.ConfigurationType, item.ParamKey)
			if allowInsert {
				toInsert = append(toInsert, item)
			}
		}
	}

	// Bath insert
	for i := 0; i < len(toInsert); i += BATCH_SIZE {
		end := i + BATCH_SIZE

		if end > len(toInsert) {
			end = len(toInsert)
		}

		subArr := toInsert[i:end]
		client.BatchCreateConfigurationDictItems(context.Background(), &pb.BatchCreateConfigurationDictRequest{
			ConfigurationDictItems: subArr,
		})

	}
	return items, nil
}

func handleDynamic(docPath string) (map[string][]string, error) {
	dynamicMap := make(map[string][]string)
	bt, err := os.ReadFile(filepath.Join(docPath, "dynamic-config.md"))
	if err != nil {
		return nil, err
	}
	lines := strings.Split(string(bt), "\n")
	currentComponent := ""
	readFile := false
	for _, line := range lines {
		if strings.Contains(line, "The following TiKV configuration") {
			currentComponent = "tikv"
			dynamicMap[currentComponent] = make([]string, 0)
			readFile = true
		}
		if strings.Contains(line, "The following PD configuration") {
			currentComponent = "pd"
			dynamicMap[currentComponent] = make([]string, 0)
			readFile = true
		}
		if readFile {
			if !strings.Contains(line, "|") {
				continue
			}
			strs := strings.Split(line, "|")
			if len(strs) != 4 {
				readFile = false
			} else {
				configName := strings.ReplaceAll(strings.TrimSpace(strs[1]), "`", "")
				dynamicMap[currentComponent] = append(dynamicMap[currentComponent], configName)
			}
		}
	}

	return dynamicMap, nil
}

var keyMappings = map[string]string{
	"Optional values":     "Optional values",
	"Available options":   "Optional values",
	"Optional value":      "Optional values",
	"Value options":       "Optional values",
	"Possible values":     "Optional values",
	"Minimum value":       "Minimum value",
	"Maximum value":       "Maximum value",
	"Default":             "Default value",
	"Default value value": "Default value",
	"Default value":       "Default value",
	"Range":               "Range",
	"Value ranges":        "Range",
	"Value range":         "Range",
}

func getAttNameFromString(s string) string {
	for k, v := range keyMappings {
		if strings.Contains(s, k) {
			return v
		}
	}
	return ""
}

func extractUnit(s string) string {
	re := regexp.MustCompile(`\d+(\.\d+)?([a-zA-Z]+)$`)
	match := re.FindStringSubmatch(s)
	if len(match) > 2 {
		return match[2]
	}
	return ""
}

func matchQuotes(s string) []string {
	r := regexp.MustCompile("`([^`]+)`")
	matches := r.FindAllStringSubmatch(s, -1)
	var groups []string
	for _, match := range matches {
		groups = append(groups, match[1])
	}
	return groups
}

func dealSpan(s string) string {
	return strings.Split(s, "<span")[0]
}

func generateTotalName(prefix, configName string) []string {
	var totalNames []string
	if prefix != "" {
		if strings.Contains(prefix, "|") {
			names := strings.Split(prefix, "|")
			for _, name := range names {
				totalNames = append(totalNames, fmt.Sprintf("%s.%s", strings.TrimSpace(name), configName))
			}
		} else {
			totalNames = append(totalNames, fmt.Sprintf("%s.%s", strings.TrimSpace(prefix), configName))
		}
	} else {
		totalNames = append(totalNames, configName)
	}
	return totalNames
}

func parseConfigurationFile(fileData string) map[string]map[string]PairedPbValue {
	configMap := make(map[string]map[string]PairedPbValue)
	prefix := ""
	configName := ""
	lines := strings.Split(fileData, "\n")
	totalNames := make([]string, 0)

	description := ""

	for _, line := range lines {
		if strings.Contains(line, "**Note:**") {
			continue
		}
		// second level name
		if strings.HasPrefix(line, "## ") {
			m := matchQuotes(line)
			if len(m) >= 1 {
				prefix = m[0]
			} else {
				prefix = strings.TrimSpace(strings.Split(line, "## ")[1])
			}
			prefix = dealSpan(prefix)
			if prefix == "Global configuration" {
				prefix = ""
			}
		}
		// param name
		if strings.HasPrefix(line, "### ") || strings.HasPrefix(line, "#### ") {
			// add the previous config name's description
			for _, totalName := range totalNames {
				configMap[totalName]["description"] = parseStringToValue(description)
			}
			m := matchQuotes(line)
			if len(m) >= 1 {
				configName = m[0]
			} else {
				fmt.Printf("config name cannot be parsed, line is %s\n", line)
				configName = strings.TrimSpace(strings.Split(line, " ")[1])
			}
			description = ""
			totalNames = generateTotalName(prefix, configName)
			for _, totalName := range totalNames {
				configMap[totalName] = make(map[string]PairedPbValue)
			}
		}
		if strings.HasPrefix(line, "+ ") || strings.HasPrefix(line, "- ") {
			description += line + "\n"
		}
		if strings.Contains(line, ":") && configName != "" {
			splitStrs := strings.Split(line, ":")
			attName := strings.TrimSpace(strings.ReplaceAll(strings.ReplaceAll(splitStrs[0], "+ ", ""), "- ", ""))
			rhs := strings.Join(splitStrs[1:], ":")
			attValue := extractAttValueFromQuotes(rhs)
			// add attribute
			formalAttName := getAttNameFromString(attName)
			if formalAttName != "" {
				for _, totalName := range totalNames {
					tmpRes := parseStringToValue(attValue)
					configMap[totalName][formalAttName] = tmpRes
				}
			}
		}
	}

	return configMap
}

func extractTiflashParam(line string) string {
	line = strings.TrimLeft(line, " \t")

	var content string
	if strings.HasPrefix(line, "#### ") {
		content = strings.TrimPrefix(line, "#### ")
	} else if strings.HasPrefix(line, "##### ") {
		content = strings.TrimPrefix(line, "##### ")
	} else {
		return ""
	}

	firstBacktick := strings.Index(content, "`")
	lastBacktick := strings.LastIndex(content, "`")
	var param string
	if firstBacktick != -1 && lastBacktick != -1 && firstBacktick < lastBacktick {
		param = content[firstBacktick+1 : lastBacktick]
	} else {
		param = content
	}

	spanIndex := strings.Index(param, "<span")
	if spanIndex != -1 {
		param = param[:spanIndex]
	}

	return strings.TrimSpace(param)
}

func parseTiflashConfiguration(fileData string) map[string]map[string]PairedPbValue {
	configMap := make(map[string]map[string]PairedPbValue)
	prefix := ""
	totalNames := make([]string, 0)
	inTiflashSection := false

	description := ""

	lines := strings.Split(fileData, "\n")
	for _, line := range lines {
		line = strings.TrimSpace(line)
		if line == "" {
			continue
		}

		if strings.HasPrefix(line, "### Configure the `tiflash.toml` file") {
			inTiflashSection = true
			continue
		}

		if strings.HasPrefix(line, "### ") && !strings.HasPrefix(line, "### Configure the `tiflash.toml` file") {
			break
		}

		if inTiflashSection {
			if strings.HasPrefix(line, "#### ") {
				totalNames = []string{extractTiflashParam(line)}
				configMap[extractTiflashParam(line)] = make(map[string]PairedPbValue)
				prefix = extractTiflashParam(line)
			}
			// param name
			if strings.HasPrefix(line, "##### ") {
				// add the previous config name's description
				for _, totalName := range totalNames {
					configMap[totalName]["description"] = parseStringToValue(description)
				}
				subfix := extractTiflashParam(line)
				description = ""
				totalNames = generateTotalName(prefix, subfix)
				for _, totalName := range totalNames {
					configMap[totalName] = make(map[string]PairedPbValue)
				}
			}
			if strings.HasPrefix(line, "+ ") || strings.HasPrefix(line, "- ") {
				description += line + "\n"
			}
			if strings.Contains(line, ":") && len(totalNames) != 0 {
				splitStrs := strings.Split(line, ":")
				attName := strings.TrimSpace(strings.ReplaceAll(strings.ReplaceAll(splitStrs[0], "+ ", ""), "- ", ""))
				rhs := strings.Join(splitStrs[1:], ":")
				attValue := extractAttValueFromQuotes(rhs)
				// add attribute
				formalAttName := getAttNameFromString(attName)
				if formalAttName != "" {
					for _, totalName := range totalNames {
						tmpRes := parseStringToValue(attValue)
						configMap[totalName][formalAttName] = tmpRes
					}
				}
			}
		}

	}

	return configMap
}

func extractAttValueFromQuotes(s string) string {
	var positions []int
	start := 0
	for {
		idx := strings.Index(s[start:], "`")
		if idx == -1 {
			break
		}
		actualIndex := start + idx
		positions = append(positions, actualIndex)
		start = actualIndex + 1
	}
	if len(positions) < 2 {
		return s
	}
	startIdx := positions[0] + 1
	endIdx := positions[1]
	return s[startIdx:endIdx]
}

type PairedPbValue struct {
	Type  pb.ConfigParamType
	Value *structpb.Value
}

func parseStringToValue(s string) PairedPbValue {
	s = strings.TrimSpace(string(s))
	s = strings.Trim(s, "\"")
	if s == `""` {
		pbVal, _ := structpb.NewValue("")
		return PairedPbValue{Type: pb.ConfigParamType_string, Value: pbVal}
	}
	var val interface{}
	var t pb.ConfigParamType
	mark := false
	if strings.ToLower(s) == "true" {
		t = pb.ConfigParamType_bool
		val = bool(true)
		mark = true
	} else if strings.ToLower(s) == "false" {
		t = pb.ConfigParamType_bool
		val = bool(false)
		mark = true
	}

	// int
	if i, err := strconv.Atoi(s); err == nil {
		t = pb.ConfigParamType_int
		val = int(i)
		mark = true
	}

	// float
	if f, err := strconv.ParseFloat(s, 64); err == nil && !mark {
		t = pb.ConfigParamType_float
		val = float64(f)
		mark = true
	}

	// json
	var js interface{}
	if !mark && strings.TrimSpace(s) != "" {
		if err := json.Unmarshal([]byte(s), &js); err == nil {
			t = pb.ConfigParamType_json
			val = js
		}
	}

	// others: string
	if val == nil {
		val = strings.TrimSpace(string(s))
		t = pb.ConfigParamType_string
	}
	pbVal, _ := structpb.NewValue(val)
	return PairedPbValue{Type: t, Value: pbVal}
}

func writeDictToCSV(path string, dict []*pb.ConfigurationDictItem) {
	file, err := os.Create(path + "/params.csv")
	if err != nil {
		fmt.Println("Cannot create file", err)
		return
	}
	defer file.Close()

	writer := csv.NewWriter(file)
	defer writer.Flush()

	// Write data
	for _, user := range dict {
		val := reflect.Indirect(reflect.ValueOf(user))
		var data []string
		for i := 0; i < val.NumField(); i++ {
			fieldName := val.Type().Field(i).Name
			if unicode.IsUpper(rune(fieldName[0])) {
				field := val.Field(i)
				var fieldStr string
				if field.Kind() == reflect.Ptr && !field.IsNil() && fieldName != "DefaultValue" {
					fieldStr = fmt.Sprintf("%v", field.Elem().Interface())
				} else {
					fieldStr = fmt.Sprintf("%v", field.Interface())
				}
				data = append(data, fieldStr)
			}
		}
		writer.Write(data)
	}
}

func specialparam(ver string) map[string]*PairedPbValue {
	res := make(map[string]*PairedPbValue)
	v, err := version.NewVersion(ver)
	if err != nil {
		fmt.Printf("Error parsing version: %s", err)
		return res
	}

	numVal, _ := structpb.NewValue(0)
	trueVal, _ := structpb.NewValue(true)
	falseVal, _ := structpb.NewValue(false)
	strVal, _ := structpb.NewValue("")
	defaultIntVal := PairedPbValue{Type: pb.ConfigParamType_int, Value: numVal}
	// defaultFloatVal := PairedPbValue{Type: pb.ConfigParamType_float, Value: numVal}
	defaultTrueVal := PairedPbValue{Type: pb.ConfigParamType_bool, Value: trueVal}
	defaultFalseVal := PairedPbValue{Type: pb.ConfigParamType_bool, Value: falseVal}
	defaultStrVal := PairedPbValue{Type: pb.ConfigParamType_string, Value: strVal}

	// schedule.tolerant-size-ratio
	res["schedule.tolerant-size-ratio"] = &defaultIntVal

	// schedule.enable-diagnostic
	v710, err := version.NewVersion("v7.1.0")
	if err != nil {
		fmt.Printf("Error parsing version: %s", err)
	}
	if v.LessThan(v710) {
		res["schedule.enable-diagnostic"] = &defaultFalseVal
	} else {
		res["schedule.enable-diagnostic"] = &defaultTrueVal
	}

	// performance.lite-init-stats
	v720, err := version.NewVersion("v7.2.0")
	if err != nil {
		fmt.Printf("Error parsing version: %s", err)
	}
	if v.LessThan(v720) {
		res["performance.lite-init-stats"] = &defaultFalseVal
	} else {
		res["performance.lite-init-stats"] = &defaultTrueVal
	}

	// isolation-read.engines
	valJSIsolationReadEngines := []string{"tikv", "tidb", "tiflash"}
	jsVal, _ := structpb.NewValue(valJSIsolationReadEngines)
	pairedIsolationReadEngines := PairedPbValue{Type: pb.ConfigParamType_json, Value: jsVal}
	res["isolation-read.engines"] = &pairedIsolationReadEngines

	// Log.timeout
	res["Log.timeout"] = &defaultIntVal

	// performance.txn-total-size-limit
	tmpIntVal, _ := structpb.NewValue(104857600)
	pairedTxnTotal := PairedPbValue{Type: pb.ConfigParamType_int, Value: tmpIntVal}
	res["performance.txn-total-size-limit"] = &pairedTxnTotal

	// performance.server-memory-quota
	res["performance.server-memory-quota"] = &defaultIntVal

	// performance.force-init-stats
	if v.LessThan(v720) {
		res["performance.force-init-stats"] = &defaultFalseVal
	} else {
		res["performance.force-init-stats"] = &defaultTrueVal
	}

	// performance.stats-load-concurrency
	v820, err := version.NewVersion("v8.2.0")
	if err != nil {
		fmt.Printf("Error parsing version: %s", err)
	}
	if v.LessThan(v820) {
		intVal5, _ := structpb.NewValue(5)
		default5Value := PairedPbValue{Type: pb.ConfigParamType_int, Value: intVal5}
		res["performance.stats-load-concurrency"] = &default5Value
	} else {
		res["performance.stats-load-concurrency"] = &defaultIntVal
	}

	// performance.txn-entry-size-limit
	intValTxnEntry, _ := structpb.NewValue(6291456)
	defaultTxnEntryValue := PairedPbValue{Type: pb.ConfigParamType_int, Value: intValTxnEntry}
	res["performance.txn-entry-size-limit"] = &defaultTxnEntryValue

	// resource-control.enabled
	res["resource-control.enabled"] = &defaultTrueVal

	//quota.foreground-cpu-time
	res["quota.foreground-cpu-time"] = &defaultIntVal

	// periodic-full-compact-start-times
	valJSEmptyStr := []string{}
	jsValEmpty, _ := structpb.NewValue(valJSEmptyStr)
	pairedEmpty := PairedPbValue{Type: pb.ConfigParamType_json, Value: jsValEmpty}
	res["periodic-full-compact-start-times"] = &pairedEmpty

	// rocksdb.defaultcf.titan.shared-blob-cache
	res["rocksdb.defaultcf.titan.shared-blob-cache"] = &defaultTrueVal

	// raftstore.store-io-pool-size
	intVal1, _ := structpb.NewValue(1)
	default1Value := PairedPbValue{Type: pb.ConfigParamType_int, Value: intVal1}
	res["raftstore.store-io-pool-size"] = &default1Value

	// import.memory-use-ratio
	floatVal03, _ := structpb.NewValue(0.3)
	defaul03Val := PairedPbValue{Type: pb.ConfigParamType_float, Value: floatVal03}
	res["import.memory-use-ratio"] = &defaul03Val

	// readpool.coprocessor.normal-concurrency
	res["readpool.coprocessor.normal-concurrency"] = &defaultIntVal

	// coprocessor.region-max-size
	res["coprocessor.region-max-size"] = &defaultIntVal

	// raftstore.raft-log-gc-size-limit
	res["raftstore.raft-log-gc-size-limit"] = &defaultIntVal

	// backup.num-threads
	res["backup.num-threads"] = &defaultIntVal

	// raftstore.raft-log-gc-count-limit
	res["raftstore.raft-log-gc-count-limit"] = &defaultIntVal

	// security.cert-allowed-cn
	res["security.cert-allowed-cn"] = &pairedEmpty

	// readpool.coprocessor.low-concurrency
	res["readpool.coprocessor.low-concurrency"] = &defaultIntVal

	// raftstore.region-split-check-diff
	res["raftstore.region-split-check-diff"] = &defaultIntVal

	// raftstore.hibernate-regions
	v502, err := version.NewVersion("v5.0.2")
	if err != nil {
		fmt.Printf("Error parsing version: %s", err)
	}
	if v.LessThan(v502) {
		res["raftstore.hibernate-regions"] = &defaultFalseVal
	} else {
		res["raftstore.hibernate-regions"] = &defaultTrueVal
	}

	// readpool.coprocessor.high-concurrency
	res["readpool.coprocessor.high-concurrency"] = &defaultIntVal

	// quota.enable-auto-tune
	res["quota.enable-auto-tune"] = &defaultFalseVal

	// readpool.unified.max-thread-count
	res["readpool.unified.max-thread-count"] = &defaultIntVal

	// raftstore.periodic-full-compact-start-max-cpu
	floatVal01, _ := structpb.NewValue(0.1)
	defaul01Val := PairedPbValue{Type: pb.ConfigParamType_float, Value: floatVal01}
	res["raftstore.periodic-full-compact-start-max-cpu"] = &defaul01Val

	// server.background-thread-count
	res["server.background-thread-count"] = &defaultIntVal

	// quota.background-cpu-time
	res["quota.background-cpu-time"] = &defaultIntVal

	// log-backup.num-threads
	res["log-backup.num-threads"] = &defaultIntVal

	// cdc.incremental-scan-concurrency
	intVal6, _ := structpb.NewValue(6)
	defaultVal6 := PairedPbValue{Type: pb.ConfigParamType_int, Value: intVal6}
	res["cdc.incremental-scan-concurrency"] = &defaultVal6

	// coprocessor.region-max-keys
	res["coprocessor.region-max-keys"] = &defaultIntVal

	// cdc.incremental-scan-threads
	intVal4, _ := structpb.NewValue(4)
	defaultVal4 := PairedPbValue{Type: pb.ConfigParamType_int, Value: intVal4}
	res["cdc.incremental-scan-threads"] = &defaultVal4

	// readpool.coprocessor.use-unified-pool
	res["readpool.coprocessor.use-unified-pool"] = &defaultFalseVal

	// readpool.storage.use-unified-pool
	res["readpool.storage.use-unified-pool"] = &defaultFalseVal

	// readpool.storage.low-concurrency
	res["readpool.storage.low-concurrency"] = &defaultIntVal

	// security.encryption.previous-master-key
	res["security.encryption.previous-master-key"] = &defaultStrVal

	// security.encryption.master-key
	res["security.encryption.master-key"] = &defaultStrVal

	// raftstore.store-max-batch-size
	res["raftstore.store-max-batch-size"] = &defaultIntVal

	// readpool.storage.high-concurrency
	res["readpool.storage.high-concurrency"] = &defaultIntVal

	// readpool.storage.normal-concurrency
	res["readpool.storage.normal-concurrency"] = &defaultIntVal

	// memory-usage-limit
	res["memory-usage-limit"] = &defaultStrVal

	// Controller.request-unit
	res["Controller.request-unit"] = &defaultStrVal

	return res
}
