package config

import (
	"bytes"
	"embed"
	"fmt"
	"log"
	"os"
	"time"

	"github.com/spf13/pflag"
	"github.com/spf13/viper"

	libConfig "be.ems/lib/config"
	libGlobal "be.ems/lib/global"
)

var cfg *viper.Viper

// 初始化程序配置
func InitConfig(configDir, assetsDir embed.FS) {
	cfg = viper.New()
	initFlag()
	initViper(configDir, assetsDir)
}

// 指定参数绑定
func initFlag() {
	// --env prod
	pflag.String("env", "prod", "Specify Run Environment Configuration local or prod")
	// --c /etc/restconf.yaml
	// -c /etc/restconf.yaml
	pflag.StringP("config", "c", "/usr/local/omc/etc/restconf.yaml", "Specify Configuration File")
	// --version
	// -V
	pVersion := pflag.BoolP("version", "V", false, "Output program version")
	// --help
	pHelp := pflag.Bool("help", false, "Viewing Help Commands")

	pflag.Parse()

	// 参数固定输出
	if *pVersion {
		buildInfo := fmt.Sprintf("OMC version: %s\n%s\n%s\n\n", libGlobal.Version, libGlobal.BuildTime, libGlobal.GoVer)
		fmt.Println(buildInfo)
		os.Exit(1)
	}
	if *pHelp {
		pflag.Usage()
		os.Exit(1)
	}

	cfg.BindPFlags(pflag.CommandLine)
}

// 配置文件读取
func initViper(configDir, assetsDir embed.FS) {
	// 如果配置文件名中没有扩展名，则需要设置Type
	cfg.SetConfigType("yaml")

	// 从 embed.FS 中读取默认配置文件内容
	configDefault, err := configDir.ReadFile("config/config.default.yaml")
	if err != nil {
		log.Fatalf("ReadFile config default file: %s", err)
		return
	}
	// 设置默认配置文件内容到 viper
	err = cfg.ReadConfig(bytes.NewReader(configDefault))
	if err != nil {
		log.Fatalf("NewReader config default file: %s", err)
		return
	}

	// 加载运行环境配置
	env := cfg.GetString("env")
	if env != "local" && env != "prod" {
		log.Fatalf("fatal error config env for local or prod : %s", env)
	}
	log.Printf("Current service environment operation configuration => %s \n", env)

	// 加载运行配置文件合并相同配置
	envPath := "config/config.prod.yaml"
	if env == "local" {
		envPath = "config/config.local.yaml"
	}
	// 从 embed.FS 中读取默认配置文件内容
	configEnv, err := configDir.ReadFile(envPath)
	if err != nil {
		log.Fatalf("ReadFile config local file: %s", err)
		return
	}
	// 设置默认配置文件内容到 viper
	err = cfg.MergeConfig(bytes.NewReader(configEnv))
	if err != nil {
		log.Fatalf("NewReader config local file: %s", err)
		return
	}

	// 合并外部使用配置
	configFile := cfg.GetString("config")
	if configFile != "" {
		configInMerge(configFile)
	}

	// 记录程序开始运行的时间点
	cfg.Set("runTime", time.Now())

	// 设置程序内全局资源访问
	cfg.Set("AssetsDir", assetsDir)
}

// 配置文件读取进行内部参数合并
func configInMerge(configFile string) {
	// 指定配置文件读取序列化
	libConfig.ReadConfig(configFile)
	uriPrefix := libConfig.GetYamlConfig().OMC.UriPrefix
	if uriPrefix != "" {
		libConfig.UriPrefix = uriPrefix
	}
	if libConfig.GetYamlConfig().TestConfig.Enabled {
		libConfig.ReadTestConfigYaml(libConfig.GetYamlConfig().TestConfig.File)
	}

	// 配置文件读取
	var v = viper.New()
	// 设置配置文件路径
	v.SetConfigFile(configFile)
	v.SetConfigType("yaml")
	// 读取配置文件
	if err := v.ReadInConfig(); err != nil {
		fmt.Printf("failure to read configuration file: %v \n", err)
		return
	}
	// 合并外层lib和features使用配置
	for key, value := range v.AllSettings() {
		// 跳过配置
		if key == "testconfig" || key == "logger" {
			continue
		}
		// 数据库配置
		if key == "database" {
			item := value.(map[string]any)
			defaultItem := cfg.GetStringMap("gorm.datasource.default")
			defaultItem["type"] = item["type"]
			defaultItem["host"] = item["host"]
			defaultItem["port"] = item["port"]
			defaultItem["username"] = item["user"]
			defaultItem["password"] = item["password"]
			defaultItem["database"] = item["name"]
			continue
		}
		cfg.Set(key, value)
	}
}

// Env 获取运行服务环境
// local prod
func Env() string {
	return cfg.GetString("env")
}

// RunTime 程序开始运行的时间
func RunTime() time.Time {
	return cfg.GetTime("runTime")
}

// Get 获取配置信息
//
// Get("server.proxy")
func Get(key string) any {
	return cfg.Get(key)
}

// Set 设置配置信息
//
// Set("redis.defaultDataSourceName", "std")
func Set(key string, value any) {
	cfg.Set(key, value)
}

// GetAssetsDirFS 访问程序内全局资源访问
func GetAssetsDirFS() embed.FS {
	return cfg.Get("AssetsDir").(embed.FS)
}

// IsAdmin 用户是否为管理员
func IsAdmin(userID string) bool {
	if userID == "" {
		return false
	}
	// 从本地配置获取user信息
	admins := Get("user.adminList").([]any)
	for _, s := range admins {
		if fmt.Sprint(s) == userID {
			return true
		}
	}
	return false
}
