package config

import (
	"errors"
	"fmt"
	"strconv"

	"github.com/beevik/etree"
)

var SerCfg *ServiceConfig

type WebConfig struct {
	ListenAddr string
	DebugMode  bool
}

type LogConfig struct {
	LogPath  string
	LogLevel int
}

type DbConfig struct {
	DbDriver  string
	DbAddress string
	DbName    string
	DbPort    string
	DbUser    string
	DbPwd     string
}

type RedisConfig struct {
	Address string
	Port    int
	TimeOut int
	ConnNum int
	DbNum   int
	Pwd     string
}

type MqConfig struct {
	Url      string
	Exchange string
}

type MongoDBConfig struct {
	HostName string
	Port     int
	DBName   string
	Username string
	Password string
}

type MySQLConfig struct {
	Host     string
	Port     int
	DBName   string
	Username string
	Password string
}

type ServiceConfig struct {
	WebCfg     WebConfig
	LogCfg     LogConfig
	DbCfg      DbConfig
	RedisCfg   RedisConfig
	MqCfg      MqConfig
	MongoDBCfg MongoDBConfig
	MySQLCfg   MySQLConfig
}

func (c *ServiceConfig) Init(path string) error {
	SerCfg = &ServiceConfig{}

	cfgfile := etree.NewDocument()
	err := cfgfile.ReadFromFile(path)
	if err != nil {
		fmt.Println("Read config file failed")
		return err
	}

	root := cfgfile.SelectElement("Configuration")
	if root == nil {
		return errors.New("read config file failed")
	}

	// web配置
	websettings := root.SelectElements("WebSetting")
	for _, setting := range websettings {
		web_listenaddr := setting.SelectElement("ListenAddress")
		if web_listenaddr == nil {
			return errors.New("read web listen address failed")
		}
		SerCfg.WebCfg.ListenAddr = web_listenaddr.SelectAttrValue("value", "0.0.0.0:8080")

		// 调试模式
		debug_mode := setting.SelectElement("DebugMode")
		if debug_mode == nil {
			return errors.New("read debug mode failed")
		}
		ret, err := strconv.ParseUint(debug_mode.SelectAttrValue("value", "0"), 10, 32)
		if err != nil {
			return errors.New("read debug mode is invalid:")
		}
		SerCfg.WebCfg.DebugMode = (ret == 1)
	}

	// 日志配置
	logsettings := root.SelectElements("LogSetting")
	for _, setting := range logsettings {
		// 日志路径
		log_path := setting.SelectElement("LogPath")
		if log_path == nil {
			return errors.New("read log path failed")
		}
		SerCfg.LogCfg.LogPath = log_path.SelectAttrValue("value", "./")

		// 日志级别
		log_level := setting.SelectElement("LogLevel")
		if log_level == nil {
			return errors.New("read log level failed")
		}
		ret, err := strconv.ParseUint(log_level.SelectAttrValue("value", "5"), 10, 32)
		if err != nil {
			return errors.New("read log level is invalid:")
		}
		SerCfg.LogCfg.LogLevel = int(ret)
	}

	// 数据库配置
	dbsettings := root.SelectElements("DbSetting")
	for _, setting := range dbsettings {
		// 数据库驱动
		db_driver := setting.SelectElement("DbDriver")
		if db_driver == nil {
			return errors.New("read db driver failed")
		}
		SerCfg.DbCfg.DbDriver = db_driver.SelectAttrValue("value", "oci8")

		// 数据库地址
		db_address := setting.SelectElement("DbAddress")
		if db_address == nil {
			return errors.New("read db address failed")
		}
		SerCfg.DbCfg.DbAddress = db_address.SelectAttrValue("value", "0.0.0.0")

		// 数据库名
		db_name := setting.SelectElement("DbName")
		if db_name == nil {
			return errors.New("read db name failed")
		}
		SerCfg.DbCfg.DbName = db_name.SelectAttrValue("value", "orcl")

		// 数据库端口
		db_port := setting.SelectElement("DbPort")
		if db_port == nil {
			return errors.New("read db port failed")
		}
		SerCfg.DbCfg.DbPort = db_port.SelectAttrValue("value", "1521")

		// 数据库名
		db_user := setting.SelectElement("DbUser")
		if db_user == nil {
			return errors.New("read db user failed")
		}
		SerCfg.DbCfg.DbUser = db_user.SelectAttrValue("value", "mtp2_test01")

		// 数据库密码
		db_pwd := setting.SelectElement("DbPwd")
		if db_pwd == nil {
			return errors.New("read db password failed")
		}
		SerCfg.DbCfg.DbPwd = db_pwd.SelectAttrValue("value", "muchinfo")
	}

	// Redis配置
	redissettings := root.SelectElements("RedisSetting")
	for _, setting := range redissettings {
		// 地址
		redis_address := setting.SelectElement("Address")
		if redis_address == nil {
			return errors.New("read redis address failed")
		}
		SerCfg.RedisCfg.Address = redis_address.SelectAttrValue("value", "127.0.0.1")

		// 端口
		redis_port := setting.SelectElement("Port")
		if redis_port == nil {
			return errors.New("read redis port failed")
		}
		ret, err := strconv.ParseUint(redis_port.SelectAttrValue("value", "5007"), 10, 32)
		if err != nil {
			return errors.New("read redis port is invalid:")
		}
		SerCfg.RedisCfg.Port = int(ret)

		// 超时时长
		redis_timeout := setting.SelectElement("Timeout")
		if redis_timeout == nil {
			return errors.New("read redis timeout failed")
		}
		ret, err = strconv.ParseUint(redis_timeout.SelectAttrValue("value", "3"), 10, 32)
		if err != nil {
			return errors.New("read redis timeout is invalid:")
		}
		SerCfg.RedisCfg.TimeOut = int(ret)

		// 连接数
		redis_connnum := setting.SelectElement("ConnNum")
		if redis_connnum == nil {
			return errors.New("read redis connnet num failed")
		}
		ret, err = strconv.ParseUint(redis_connnum.SelectAttrValue("value", "1"), 10, 32)
		if err != nil {
			return errors.New("read redis connnet num is invalid:")
		}
		SerCfg.RedisCfg.ConnNum = int(ret)

		// 库编号
		redis_dbnum := setting.SelectElement("DbNum")
		if redis_dbnum == nil {
			return errors.New("read redis db num failed")
		}
		ret, err = strconv.ParseUint(redis_dbnum.SelectAttrValue("value", "0"), 10, 32)
		if err != nil {
			return errors.New("read redis db num is invalid:")
		}
		SerCfg.RedisCfg.DbNum = int(ret)

		// 密码
		redis_pwd := setting.SelectElement("Pwd")
		if redis_pwd == nil {
			return errors.New("read redis password failed")
		}
		SerCfg.RedisCfg.Pwd = redis_pwd.SelectAttrValue("value", "")
	}

	// RabbitMQ配置
	mqsettings := root.SelectElements("MqSetting")
	for _, setting := range mqsettings {
		// url
		url := setting.SelectElement("Url")
		if url == nil {
			return errors.New("read rabbitmq url failed")
		}
		SerCfg.MqCfg.Url = url.SelectAttrValue("value", "")

		// exchange
		exchange := setting.SelectElement("Exchange")
		if exchange == nil {
			return errors.New("read rabbitmq exchange failed")
		}
		SerCfg.MqCfg.Exchange = exchange.SelectAttrValue("value", "entry")
	}

	// MongoDB配置
	mongodbsettings := root.SelectElements("MongoDBSetting")
	for _, setting := range mongodbsettings {
		// 主机地址
		hostName := setting.SelectElement("HostName")
		if hostName == nil {
			return errors.New("read mongondb hostname failed")
		}
		SerCfg.MongoDBCfg.HostName = hostName.SelectAttrValue("value", "")

		// 端口
		port := setting.SelectElement("Port")
		if port == nil {
			return errors.New("read mongondb port failed")
		}
		ret, err := strconv.ParseUint(port.SelectAttrValue("value", "5025"), 10, 32)
		if err != nil {
			return errors.New("read mongondb port failed")
		}
		SerCfg.MongoDBCfg.Port = int(ret)

		// 数据库名
		dbname := setting.SelectElement("DBName")
		if dbname == nil {
			return errors.New("read mongondb dbname failed")
		}
		SerCfg.MongoDBCfg.DBName = dbname.SelectAttrValue("value", "")

		// 用户名
		username := setting.SelectElement("Username")
		if username == nil {
			return errors.New("read mongondb username failed")
		}
		SerCfg.MongoDBCfg.Username = username.SelectAttrValue("value", "")

		// 密码
		password := setting.SelectElement("Password")
		if password == nil {
			return errors.New("read mongondb password failed")
		}
		SerCfg.MongoDBCfg.Password = password.SelectAttrValue("value", "")
	}

	// MySQL配置
	mysqlsettings := root.SelectElements("MySQLSetting")
	for _, setting := range mysqlsettings {
		// 主机地址
		host := setting.SelectElement("Host")
		if host == nil {
			return errors.New("read mysql host failed")
		}
		SerCfg.MySQLCfg.Host = host.SelectAttrValue("value", "")

		// 端口
		port := setting.SelectElement("Port")
		if port == nil {
			return errors.New("read mysql port failed")
		}
		ret, err := strconv.ParseUint(port.SelectAttrValue("value", "3306"), 10, 32)
		if err != nil {
			return errors.New("read mysql port failed")
		}
		SerCfg.MySQLCfg.Port = int(ret)

		// 数据库名
		dbname := setting.SelectElement("DBName")
		if dbname == nil {
			return errors.New("read mysql dbname failed")
		}
		SerCfg.MySQLCfg.DBName = dbname.SelectAttrValue("value", "")

		// 用户名
		username := setting.SelectElement("Username")
		if username == nil {
			return errors.New("read mysql username failed")
		}
		SerCfg.MySQLCfg.Username = username.SelectAttrValue("value", "")

		// 密码
		password := setting.SelectElement("Password")
		if password == nil {
			return errors.New("read mysql password failed")
		}
		SerCfg.MySQLCfg.Password = password.SelectAttrValue("value", "")
	}

	return nil
}

func (c *ServiceConfig) GetWebListenAddr() string {
	return SerCfg.WebCfg.ListenAddr
}

func (c *ServiceConfig) GetDebugMode() bool {
	return SerCfg.WebCfg.DebugMode
}

func (c *ServiceConfig) GetLogSetting() (string, int) {
	return SerCfg.LogCfg.LogPath, SerCfg.LogCfg.LogLevel
}

func (c *ServiceConfig) GetDbDriver() string {
	return SerCfg.DbCfg.DbDriver
}

func (c *ServiceConfig) GetDbSource() string {
	dbsource := fmt.Sprintf("%s/%s@%s:%s/%s",
		SerCfg.DbCfg.DbUser,
		SerCfg.DbCfg.DbPwd,
		SerCfg.DbCfg.DbAddress,
		SerCfg.DbCfg.DbPort,
		SerCfg.DbCfg.DbName)

	return dbsource
}

func (c *ServiceConfig) GetRedisAddress() string {
	redisaccress := fmt.Sprintf("%s:%d",
		SerCfg.RedisCfg.Address,
		SerCfg.RedisCfg.Port)

	return redisaccress
}

func (c *ServiceConfig) GetRedisPwd() string {
	return SerCfg.RedisCfg.Pwd
}

func (c *ServiceConfig) GetRedisDbNum() int {
	return SerCfg.RedisCfg.DbNum
}

func (c *ServiceConfig) GetRedisConnNum() int {
	return SerCfg.RedisCfg.ConnNum
}

func (c *ServiceConfig) GetRedisTimeout() int {
	return SerCfg.RedisCfg.TimeOut
}

func (c *ServiceConfig) GetMongoDBHostname() string {
	return SerCfg.MongoDBCfg.HostName
}

func (c *ServiceConfig) GetMongoDBPort() int {
	return SerCfg.MongoDBCfg.Port
}

func (c *ServiceConfig) GetMongoDBDBName() string {
	return SerCfg.MongoDBCfg.DBName
}

func (c *ServiceConfig) GetMongoDBUsername() string {
	return SerCfg.MongoDBCfg.Username
}

func (c *ServiceConfig) GetMongoDBPassword() string {
	return SerCfg.MongoDBCfg.Password
}

func (c *ServiceConfig) GetMySQLHost() string {
	return SerCfg.MySQLCfg.Host
}

func (c *ServiceConfig) GetMySQLPort() int {
	return SerCfg.MySQLCfg.Port
}

func (c *ServiceConfig) GetMySQLDBName() string {
	return SerCfg.MySQLCfg.DBName
}

func (c *ServiceConfig) GetMySQLUsername() string {
	return SerCfg.MySQLCfg.Username
}

func (c *ServiceConfig) GetMySQLPassword() string {
	return SerCfg.MySQLCfg.Password
}
