package ne

import (
	"encoding/json"
	"fmt"
	"log"
	"os"
	"path/filepath"
	"sort"
	"strconv"
	"strings"
	"testing"
	"time"

	"be.ems/src/modules/ne/model"
	"gopkg.in/yaml.v3"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
)

const (
	// 数据库
	DbHost    = "192.168.9.58"
	DbPort    = 13306
	DbUser    = "root"
	DbPassswd = "1000omc@kp!"
	DbName    = "omc_db_mainv2"
	// 配置文件路径
	configParamDir = "../../../local/param"
	// configParamFile = "*" // 目录下全部更新
	configParamFile = "amf_param_config.yaml" // 单文件更新
)

func TestConfig(t *testing.T) {
	fileNameList, err := getDirFileNameList(configParamDir)
	if err != nil {
		log.Fatal(err)
		return
	}

	if configParamFile == "*" {
		for _, v := range fileNameList {
			params := parseData(filepath.Join(configParamDir, v))
			if params == nil {
				return
			}
			saveData(params)
		}
	} else {
		params := parseData(filepath.Join(configParamDir, configParamFile))
		if params == nil {
			return
		}
		saveData(params)
	}
}

// ========= Main =============

// parseData 文件转map数据
func parseData(filePaht string) []map[string]string {
	data, err := parseStrToMap(filePaht)
	if err != nil {
		log.Printf("parseStrToMap => %s", err.Error())
		return nil
	}
	params, err := parseParamConfig(data)
	if err != nil {
		log.Printf("parseParamConfig => %s", err.Error())
		return nil
	}
	return params
}

// saveData 保存数据
func saveData(params []map[string]string) {
	// 定义排序函数
	sort.Slice(params, func(i, j int) bool {
		paramSortI := params[i]["paramSort"]
		if len(paramSortI) == 0 || paramSortI == "" {
			paramSortI = "0"
		}
		paramSortJ := params[j]["paramSort"]
		if len(paramSortJ) == 0 || paramSortJ == "" {
			paramSortJ = "0"
		}
		// 将 age 字段转换为整数进行比较
		si, _ := strconv.Atoi(paramSortI)
		sj, _ := strconv.Atoi(paramSortJ)
		return si < sj
	})
	// 遍历插入
	for _, v := range params {
		// 排序
		paramSort := v["paramSort"]
		if len(paramSort) == 0 || paramSort == "" {
			paramSort = "0"
		}
		sort, err := strconv.ParseInt(paramSort, 10, 64)
		if err != nil {
			sort = 0
		}

		// 可见性 默认public
		visible := v["visible"]
		if len(visible) == 0 || visible == "" {
			visible = "public"
		}

		neConfig := model.NeConfig{
			NeType:       v["neType"],
			ParamName:    v["paramName"],
			ParamDisplay: v["paramDisplay"],
			ParamType:    v["paramType"],
			ParamJson:    v["paramJson"],
			ParamPerms:   v["paramPerms"],
			Visible:      visible,
			ParamSort:    sort,
		}
		neConfig.ID = saveDB(neConfig)
		log.Println(neConfig.ID, neConfig.NeType, neConfig.ParamDisplay)
	}
}

// ========= DB =============

var gdb *gorm.DB

// connDB 连接到数据库
func connDB() *gorm.DB {
	if gdb != nil {
		return gdb
	}

	dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local", DbUser, DbPassswd, DbHost, DbPort, DbName)
	newLogger := logger.New(
		log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer
		logger.Config{
			SlowThreshold:             time.Minute,  // Slow SQL threshold
			LogLevel:                  logger.Error, // Log level
			IgnoreRecordNotFoundError: true,         // Ignore ErrRecordNotFound error for logger
			ParameterizedQueries:      true,         // Don't include params in the SQL log
			Colorful:                  false,        // Disable color
		},
	)
	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{Logger: newLogger})
	if err != nil {
		log.Fatalln(err)
	}
	gdb = db
	return gdb
}

// saveDB 表插入或更新
func saveDB(s model.NeConfig) int64 {
	db := connDB()
	// 检查是否存在
	var id int64
	db.Raw("SELECT id FROM ne_config WHERE ne_type = ? AND param_name = ?", s.NeType, s.ParamName).Scan(&id)
	// 更新时间
	s.UpdateTime = time.Now().UnixMilli()
	if id > 0 {
		s.ID = id
		db.Save(&s)
	} else {
		db.Create(&s)
	}
	return s.ID
}

// ========= Utils =============

// getDirFileNameList 获取文件目录下所有文件名称，不含目录名称
func getDirFileNameList(dirPath string) ([]string, error) {
	fileNames := []string{}

	dir, err := os.Open(dirPath)
	if err != nil {
		return fileNames, nil
	}
	defer dir.Close()

	fileInfos, err := dir.Readdir(-1)
	if err != nil {
		return fileNames, err
	}

	for _, fileInfo := range fileInfos {
		if fileInfo.Mode().IsRegular() {
			fileNames = append(fileNames, fileInfo.Name())
		}
	}

	return fileNames, nil
}

// parseStrToMap 解析内容string到map
func parseStrToMap(filePath string) (map[string]any, error) {
	// 读取文件内容
	bytes, err := os.ReadFile(filePath)
	if err != nil {
		return nil, err
	}
	content := string(bytes)
	var configMap map[string]any
	err = yaml.Unmarshal([]byte(content), &configMap)

	return configMap, err
}

// parseParamConfig 解析内容文件数据
func parseParamConfig(data map[string]any) ([]map[string]string, error) {
	paramMapArr := make([]map[string]string, 0)
	for k, v := range data {
		for ik, iv := range v.(map[string]any) {
			itemMap := make(map[string]string)
			itemMap["neType"] = strings.ToUpper(k)
			itemMap["paramName"] = ik
			for iik, iiv := range iv.(map[string]any) {
				switch iik {
				case "display":
					itemMap["paramDisplay"] = iiv.(string)
				case "sort":
					itemMap["paramSort"] = fmt.Sprint(iiv)
				case "visible":
					itemMap["visible"] = fmt.Sprint(iiv)
				case "perms", "method":
					itemMap["paramPerms"] = iiv.(string)
				case "list", "array": // 参数类型为数组
					itemMap["paramType"] = iik
					strByte, _ := json.Marshal(iiv)
					itemMap["paramJson"] = string(strByte)
				}
			}
			paramMapArr = append(paramMapArr, itemMap)
		}
	}
	return paramMapArr, nil
}
