package config

import (
	"flag"
	"fmt"
	"os"
	"strings"

	"be.ems/lib/global"
	"be.ems/lib/log"
	"be.ems/sshsvc/logmml"

	"gopkg.in/yaml.v3"
)

type DbConfig struct {
	Type      string `yaml:"type"`
	User      string `yaml:"user"`
	Password  string `yaml:"password"`
	Host      string `yaml:"host"`
	Port      string `yaml:"port"`
	Name      string `yaml:"name"`
	ConnParam string `yaml:"connParam,omitempty"`
	Backup    string `yaml:"backup"`
}

// Yaml struct of config
type YamlConfig struct {
	Logger struct {
		File     string `yaml:"file"`
		Level    string `yaml:"level"`
		Duration int    `yaml:"duration"`
		Count    int    `yaml:"count"`
	} `yaml:"logger"`

	Logmml struct {
		File     string `yaml:"file"`
		Duration int    `yaml:"duration"`
		Count    int    `yaml:"count"`
		Level    string `yaml:"level"`
	} `yaml:"logmml"`

	Sshd struct {
		ListenAddr string `yaml:"listenAddr"`
		ListenPort uint16 `yaml:"listenPort"`
		PrivateKey string `yaml:"privateKey"`
		MaxConnNum int    `yaml:"maxConnNum"`
		Timeout    uint16 `yaml:"timeout"`
		Session    string `yaml:"session"`
		MmlHome    string `yaml:"mmlHome"`
		UserName   string `yaml:"userName"`
		Password   string `yaml:"password"`
		AuthType   string `yaml:"authType"`
		TagNE      string `yaml:"tagNE"`
	} `yaml:"sshd"`

	TelnetServer struct {
		ListenAddr string `yaml:"listenAddr"`
		ListenPort uint16 `yaml:"listenPort"`
		MaxConnNum int    `yaml:"maxConnNum"`
		Timeout    uint16 `yaml:"timeout"`
		Session    string `yaml:"session"`
		MmlHome    string `yaml:"mmlHome"`
		UserName   string `yaml:"userName"`
		Password   string `yaml:"password"`
		AuthType   string `yaml:"authType"`
		TagNE      string `yaml:"tagNE"`
	} `yaml:"telnetServer"`

	SNMPServer struct {
		ListenAddr string `yaml:"listenAddr"`
		ListenPort uint16 `yaml:"listenPort"`
		UserName   string `yaml:"userName"`
		AuthPass   string `yaml:"authPass"`
		AuthProto  string `yaml:"authProto"`
		PrivPass   string `yaml:"privPass"`
		PrivProto  string `yaml:"privProto"`
		EngineID   string `yaml:"engineID"`
		TrapPort   uint16 `yaml:"trapPort"`
		TrapListen bool   `yaml:"trapListen"`
		TrapBool   bool   `yaml:"trapBool"`
		TrapTick   uint16 `yaml:"trapTick"`
		TimeOut    uint16 `yaml:"timeOut"`
		TrapTarget string `yaml:"trapTarget"`
	} `yaml:"snmpServer"`

	Database DbConfig `yaml:"database"`

	OMC struct {
		HttpUri   string `yaml:"httpUri"`
		UserCrypt string `yaml:"userCrypt"`
	} `yaml:"omc"`
}

var yamlConfig YamlConfig = NewYamlConfig()

// set default value for yaml config
func NewYamlConfig() YamlConfig {
	return YamlConfig{
		Database: DbConfig{
			Type:      "mysql",
			ConnParam: "charset=utf8mb4&collation=utf8mb4_general_ci&parseTime=True&interpolateParams=True",
		},
	}
}

func ReadConfig(configFile string) {
	yamlFile, err := os.ReadFile(configFile)
	if err != nil {
		fmt.Println("Read yaml config file error:", err)
		os.Exit(2)
	}

	err = yaml.Unmarshal(yamlFile, &yamlConfig)
	if err != nil {
		fmt.Println("Unmarshal error:", err)
		os.Exit(3)
	}
}

func GetYamlConfig() *YamlConfig {
	return &yamlConfig
}

func GetLogLevel() log.LogLevel {
	var logLevel log.LogLevel
	switch strings.ToLower(yamlConfig.Logger.Level) {
	case "trace":
		logLevel = log.LOG_TRACE
	case "info":
		logLevel = log.LOG_INFO
	case "debug":
		logLevel = log.LOG_DEBUG
	case "warn":
		logLevel = log.LOG_WARN
	case "error":
		logLevel = log.LOG_ERROR
	case "fatal":
		logLevel = log.LOG_FATAL
	case "off":
		logLevel = log.LOG_OFF
	default:
		logLevel = log.LOG_DEBUG
	}
	return logLevel
}

func GetLogMmlLevel() logmml.LogLevel {
	var logLevel logmml.LogLevel
	switch strings.ToLower(yamlConfig.Logmml.Level) {
	case "cmd", "command":
		logLevel = logmml.LOG_CMD
	case "ret", "result":
		logLevel = logmml.LOG_RET
	default:
		logLevel = logmml.LOG_CMD
	}
	return logLevel
}

func GetDefaultUserAgent() string {
	return "OMC-sshsvc/" + global.Version
}

const DefaultConfigFile = "./etc/sshsvc.yaml"

func init() {
	cfile := flag.String("c", DefaultConfigFile, "config file")
	pv := flag.Bool("v", false, "print version")
	pversion := flag.Bool("version", false, "print version")
	ph := flag.Bool("h", false, "print help")
	phelp := flag.Bool("help", false, "print help")

	flag.Parse()
	if *pv || *pversion {
		fmt.Printf("OMC sshsvc version: %s\n%s\n%s\n\n", global.Version, global.BuildTime, global.GoVer)
		os.Exit(0)
	}
	if *ph || *phelp {
		flag.Usage()
		os.Exit(0)
	}

	ReadConfig(*cfile)
}
