package component

import (
	"fmt"
	"gitea.party/public-messag-service/config"
	"gitea.party/public-messag-service/config/app_ser"
	glogger "gitea.party/public-messag-service/config/logger"
	"github.com/urfave/cli/v2"
	"gorm.io/gorm/logger"
	"strings"
	"time"
)

type MySQL struct {
	Cfg  config.ComponentMysql
	Clts map[string]*MySQLClient
	Log  MysqlLogger
}

func (c *MySQL) SetLogLevel(v int) {
	// log leve
	nVal := logger.Error
	switch v {
	case glogger.Info:
		nVal = logger.Info
	case glogger.Warn:
		nVal = logger.Warn
	case glogger.Error:
		nVal = logger.Error
	}
	c.Log.level = nVal
}

func (c *MySQL) CliFlags() []cli.Flag {
	fs := make([][]cli.Flag, 0, len(c.Clts)+1)
	fs = append(fs, []cli.Flag{
		&cli.IntFlag{Name: "mysql-threshold", Usage: "mysql slow threshold", Value: 300, Destination: &c.Cfg.SlowThreshold},
		&cli.IntFlag{Name: "mysql-op-timeout", Usage: "mysql operation timeout", Value: 15, Destination: &c.Cfg.OpTimeout},
	})
	for name, clt := range c.Clts {
		fs = append(fs, clt.CliFlags(name))
	}
	l := 0
	for k := range fs {
		l += len(fs[k])
	}
	ret := make([]cli.Flag, 0, l)
	for k := range fs {
		ret = append(ret, fs[k]...)
	}
	return ret
}

func (c *MySQL) Init(l glogger.Interface, cfg *app_ser.AppConfig, _ *cli.Context) error {
	// 设置日志等级
	c.Log.SetLogger(l)
	c.Log.slowThreshold = time.Duration(c.Cfg.SlowThreshold) * time.Millisecond
	switch cfg.Env() {
	case app_ser.EnvLocal:
		c.SetLogLevel(glogger.Info)
	case app_ser.EnvDebug:
		c.SetLogLevel(glogger.Warn)
	case app_ser.EnvProd:
		c.SetLogLevel(glogger.Error)
	}

	// 打印链接信息
	for k, v := range c.Clts {
		msg := fmt.Sprintf("Init MySQL (%s) config", k)
		v.Init(cfg.Env(), c)
		if config.PrintfDSN {
			var slave string
			cCfg := v.Config()
			if len(cCfg.Slave) > 0 {
				ss := make([]string, 0, len(cCfg.Slave))
				for sk := range cCfg.Slave {
					ss = append(ss, cCfg.Slave[sk].GetPrintDSN())
				}
				slave = "[" + strings.Join(ss, ";") + "]"
			}

			msg = fmt.Sprintf("%s (%s%s)", msg, cCfg.Master.GetPrintDSN(), slave)
		}
		c.Log.log.WarnForce(msg)
	}
	return nil
}

func (c *MySQL) Run() error {
	for name := range c.Clts {
		if err := c.LoadOne(name); err != nil {
			return err
		}
	}
	return nil
}

func (c *MySQL) LoadOne(name string) (err error) {
	if clt, ok := c.Clts[name]; ok {
		err = clt.Load(name)
	} else {
		err = fmt.Errorf("MySQL (%s) config no find", name)
	}
	return err
}

func (c *MySQL) Close() error {
	return nil
}